├── README.md ├── analyseSubject.asv ├── mainScript.asv ├── getFreqBandsScript.m ├── getLabels.m ├── matlab.gitignore ├── getFeaturesFromSubject.m ├── addFeaturesToSubject.m ├── dimensionReductionAverage.m ├── loadData.m ├── process2struct.asv ├── makeFeatureStruct.m ├── mainProcessDataScript.m ├── getElectrodeMapping.m ├── makeDEAPstruct.m ├── freqBands.m ├── ClassifySVM.m ├── ClassifySVM.asv └── extractFeaturesFromPSD.m /README.md: -------------------------------------------------------------------------------- 1 | # emotionRecognition 2 | 3 | Emotion Recognition Using DEAP Database 4 | -------------------------------------------------------------------------------- /analyseSubject.asv: -------------------------------------------------------------------------------- 1 | function [sub] = getFeaturesFromSubject(sub) 2 | 3 | % Iterate over each video 4 | vidNames = fieldnames(sub); 5 | for i = 1:size(vidNames) 6 | vid = sub.(char(vidNames(i))); 7 | vid.fb = freqBands(vid.data, FS, BANDS); 8 | vid.features = extractFeatures(vid); 9 | 10 | end -------------------------------------------------------------------------------- /mainScript.asv: -------------------------------------------------------------------------------- 1 | %% Get deapData 2 | path = 'T:\\CRB\\DEAP\\data\\'; 3 | deapData = makeDEAPstruct(path); 4 | 5 | %Initialize EEG Var 6 | % EEG = pop_importdata('dataformat','matlab',... 7 | % 'nbchan',32,'data','T:\\CRB\\DEAP\\s01_1.mat',... 8 | % 'srate',128,'subject','s1','pnts',0,'xmin',0,'session',[]); 9 | 10 | %% Get freq data -------------------------------------------------------------------------------- /getFreqBandsScript.m: -------------------------------------------------------------------------------- 1 | eeg_data = deapData.s7.v4.data.eeg; 2 | Fs = 128; 3 | bands = struct(); 4 | bands.freq = [ 5 | [1 3] 6 | [4 7] 7 | [8 13] 8 | [14 30] 9 | [31 50] 10 | ]; 11 | 12 | bands.names = {'delta' 'theta' 'alpha' 'beta' 'gamma'}; 13 | 14 | fb = freqBands(eeg_data(1:32,:),Fs,bands); 15 | 16 | figure; 17 | bar(fb.bands.med, 10*log10(fb.f.pb_tot)) 18 | set(gca, 'XTick', fb.bands.med, 'XTickLabel', fb.bands.names); 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /getLabels.m: -------------------------------------------------------------------------------- 1 | function [labels] = getLabels(deapData) 2 | labels = zeros(32,40,2); 3 | 4 | subNames = fieldnames(deapData.data); 5 | vidNames = fieldnames(deapData.data.(char(subNames(1)))); 6 | 7 | %Iterate over subjects and videos 8 | for sub = 1:size(labels,1) 9 | for vid = 1:size(labels,2) 10 | %first label is Valance, seconds is Arousal 11 | labels(sub,vid,:) = deapData.data.(char(subNames(sub))).(char(vidNames(vid))).labels(1:2); 12 | end 13 | end 14 | end -------------------------------------------------------------------------------- /matlab.gitignore: -------------------------------------------------------------------------------- 1 | ##--------------------------------------------------- 2 | ## Remove autosaves generated by the Matlab editor 3 | ## We have git for backups! 4 | ##--------------------------------------------------- 5 | 6 | # Windows default autosave extension 7 | *.asv 8 | 9 | # OSX / *nix default autosave extension 10 | *.m~ 11 | 12 | # Compiled MEX binaries (all platforms) 13 | *.mex* 14 | 15 | # Simulink Code Generation 16 | slprj/ 17 | 18 | # Session info 19 | octave-workspace 20 | -------------------------------------------------------------------------------- /getFeaturesFromSubject.m: -------------------------------------------------------------------------------- 1 | function [features] = getFeaturesFromSubject(sub, info) 2 | features = struct(); 3 | 4 | % Iterate over each video 5 | FS = info.fs; 6 | BANDS = info.bands; 7 | eMAP = info.mapping; 8 | 9 | vidNames = fieldnames(sub); 10 | for i = 1:size(vidNames) 11 | % Get video 12 | vid = sub.(char(vidNames(i))); 13 | 14 | % add freq analysis 15 | vid = freqBands(vid.data.eeg, FS, BANDS); 16 | 17 | % get features 18 | features.(char(vidNames(i))) = extractFeaturesFromPSD(vid.f.pbc,eMAP); 19 | end 20 | 21 | -------------------------------------------------------------------------------- /addFeaturesToSubject.m: -------------------------------------------------------------------------------- 1 | function [sub] = addFeaturesToSubject(sub, info) 2 | 3 | % Iterate over each video 4 | FS = info.fs; 5 | BANDS = info.bands; 6 | eMAP = info.mapping; 7 | 8 | vidNames = fieldnames(sub); 9 | for i = 1:size(vidNames) 10 | % Get video 11 | vid = sub.(char(vidNames(i))); 12 | 13 | % add freq analysis 14 | vid.fb = freqBands(vid.data.eeg, FS, BANDS); 15 | 16 | % add features 17 | vid.features = extractFeatures(vid.fb.f.pbc,eMAP); 18 | 19 | % Save changes 20 | sub.(char(vidNames(i))) = vid; 21 | end 22 | 23 | -------------------------------------------------------------------------------- /dimensionReductionAverage.m: -------------------------------------------------------------------------------- 1 | %% Dimension Reduction by Averaging 2 | function avgFeaturesPerSubject = dimensionReductionAverage(featureData) 3 | avgFeaturesPerSubject = zeros(32,40,5); 4 | featureName = 'de'; 5 | subNames = fieldnames(featureData); 6 | vidNames = fieldnames(featureData.(char(subNames(1)))); 7 | 8 | for sub = 1:size(avgFeaturesPerSubject,1) 9 | for vid = 1:size(avgFeaturesPerSubject,2) 10 | features = featureData.(char(subNames(sub))).(char(vidNames(vid))); 11 | avgFeaturesPerSubject(sub,vid,:) = mean(features.(featureName),1); 12 | end 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /loadData.m: -------------------------------------------------------------------------------- 1 | basePath = 'C:\\Users\\NYUAD\\Desktop\\CRB\\DEAP\\'; 2 | subjectPath = 'data\\s01.mat'; 3 | 4 | % Load data for individual subject 5 | s01 = load(basePath+subjectPath); 6 | s01Data = s01.data(); 7 | s01Labels = s01.labels(); 8 | % Select data for Video 1 and Channels 1-32 9 | s01_1 = squeeze(s01Data(1,1:32,:)); 10 | save('C:\\Users\\NYUAD\\Desktop\\CRB\\DEAP\\s01_1.mat', 's01_1'); 11 | 12 | % Import data into EEGLAB from Matlab variable 13 | EEG = pop_importdata('dataformat','matlab','nbchan',32,'data',... 14 | 'C:\\Users\\NYUAD\\Desktop\\CRB\\DEAP\\s01_1.mat',... 15 | 'srate',128,'pnts',0,'xmin',0); -------------------------------------------------------------------------------- /process2struct.asv: -------------------------------------------------------------------------------- 1 | function [deapData] = makeDEAPstruct(path) 2 | path = 'C:\\Users\\NYUAD\\Desktop\\CRB\\DEAP\\data\\'; 3 | deapData = struct(); 4 | 5 | for i = 1:32 6 | disp(i); 7 | if(i < 10) 8 | subject = load(strcat(path, 's0', num2str(i), '.mat')); 9 | else 10 | subject = load(strcat(path, 's', num2str(i), '.mat')); 11 | end 12 | subjectID = strcat('s', num2str(i)); 13 | for v = 1:40.0 14 | videoID = strcat('v', num2str(v)); 15 | deapData.(subjectID).(videoID).labels = subject.labels(); 16 | deapData.(subjectID).(videoID).data = ... 17 | struct('eeg', squeeze(subject.data(v,1:32,:)),... 18 | 'other',squeeze(subject.data(v,33:40,:))); 19 | end 20 | end 21 | 22 | end 23 | 24 | %EEG.data = deapData.s4.v6.data.eeg 25 | 26 | %save(strcat(path,'deapData.'), 'deapData', '-v7.3'); 27 | 28 | 29 | -------------------------------------------------------------------------------- /makeFeatureStruct.m: -------------------------------------------------------------------------------- 1 | function [Features] = makeFeatureStruct(deapData) 2 | % Past filepaths 3 | % path = 'T:\\CRB\\DEAP\\data\\'; 4 | % path = 'C:\\Users\\NYUAD\\Desktop\\CRB\\DEAP\\data\\'; 5 | 6 | %Declare Struct 7 | Features = struct(); 8 | fprintf(1,'processing subjects: 0'); 9 | 10 | %For all files (each file contains data for one subject) 11 | subNames = fieldnames(deapData.data); 12 | for i = 1:length(subNames) 13 | %filenames less than 9 prepended with 0 14 | if(i < 10) 15 | fprintf(1,'\b%d',i); 16 | else 17 | fprintf(1,'\b\b%d',i); 18 | end 19 | Features.(char(subNames(i))) = getFeaturesFromSubject(... 20 | deapData.data.(char(subNames(i))), deapData.info); 21 | end 22 | 23 | % Very slow/ unopenable 24 | %save(strcat(path,'deapData.'), 'deapData', '-v7.3'); 25 | end 26 | 27 | % Access like so: 28 | %EEG.data = deapData.s4.v6.data.eeg 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /mainProcessDataScript.m: -------------------------------------------------------------------------------- 1 | %% Get deapData 2 | PATH = 'T:\\CRB\\DEAP\\data\\'; 3 | deapData.data = makeDEAPstruct(PATH); 4 | 5 | %Initialize EEG Var 6 | % EEG = pop_importdata('dataformat','matlab',... 7 | % 'nbchan',32,'data','T:\\CRB\\DEAP\\s01_1.mat',... 8 | % 'srate',128,'subject','s1','pnts',0,'xmin',0,'session',[]); 9 | 10 | %% Recording Data 11 | % Frequency 12 | deapData.info.fs = 128; 13 | 14 | % Eletrode Mapping 15 | deapData.info.mapping = getElectrodeMapping(); 16 | 17 | 18 | %% Analysis Data 19 | % Frequency Bands of interest 20 | BANDS = struct(); 21 | BANDS.freq = [ 22 | [1 3] 23 | [4 7] 24 | [8 13] 25 | [14 30] 26 | [31 50] 27 | ]; 28 | 29 | BANDS.names = {'delta' 'theta' 'alpha' 'beta' 'gamma'}; 30 | deapData.info.bands = BANDS; 31 | 32 | %% Add features to DEAP struct 33 | %%deapData.data.s1 = addFeaturesToSubject(deapData.data.s1, deapData.info); 34 | 35 | %% Make new feature struct 36 | featureData = makeFeatureStruct(deapData); -------------------------------------------------------------------------------- /getElectrodeMapping.m: -------------------------------------------------------------------------------- 1 | function [mappings] = getElectrodeMapping() 2 | mappings = struct(); 3 | 4 | % Electrode/Channel Mapping 5 | mappings.channels = containers.Map({'Fp1', 'AF3', 'F3', 'F7', 'FC5', 'FC1',... 6 | 'C3', 'T7', 'CP5', 'CP1', 'P3', 'P7', 'PO3', 'O1', 'Oz', 'Pz',... 7 | 'Fp2', 'AF4', 'Fz', 'F4', 'F8', 'FC6', 'FC2', 'Cz', 'C4', 'T8',... 8 | 'CP6', 'CP2', 'P4', 'P8', 'PO4', 'O2'} , {1, 2, 3, 4, 5, 6, 7, 8,... 9 | 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,... 10 | 26, 27, 28, 29, 30, 31, 32}); 11 | 12 | % Hemispheric assymmetry Pairs (between the left and right hemisphere) 13 | mappings.assymPairs ={'Fp1' 'Fp2'; 'F7' 'F8'; 'F3' 'F4'; ... 14 | 'T7' 'T8'; 'P7' 'P8'; 'C3' 'C4'; 'P3' 'P4'; ... 15 | 'O1' 'O2'; 'AF3' 'AF4'; 'F7' 'F8'; 'FC5' 'FC6'; 'FC1' 'FC2'; ... 16 | 'CP5' 'CP6'; 'CP1' 'CP2'; 'PO3' 'PO4'}; 17 | 18 | % access like assymPairs{7,2} 19 | 20 | % Caudality Pairs (in frontal-posterior direction) 21 | mappings.caudPairs = {'FC5' 'CP5'; 'FC1' 'CP1'; 'FC2' 'CP2'; 'FC6' 'CP6'; ... 22 | 'F7' 'P7'; 'F3' 'P3'; 'Fz' 'Pz'; 'F4' 'P4'; 'F8' 'P8'; ... 23 | 'Fp1' 'O1'; 'Fp2' 'O2'}; 24 | 25 | end 26 | -------------------------------------------------------------------------------- /makeDEAPstruct.m: -------------------------------------------------------------------------------- 1 | function [deapData] = makeDEAPstruct(path) 2 | % Past filepaths 3 | % path = 'T:\\CRB\\DEAP\\data\\'; 4 | % path = 'C:\\Users\\NYUAD\\Desktop\\CRB\\DEAP\\data\\'; 5 | 6 | %Declare Struct 7 | deapData = struct(); 8 | fprintf(1,'processing subjects: 0'); 9 | 10 | %For all files (each file contains data for one subject) 11 | for i = 1:32 12 | 13 | %filenames less than 9 prepended with 0 14 | if(i < 10) 15 | fprintf(1,'\b%d',i); 16 | subject = load(strcat(path, 's0', num2str(i), '.mat')); 17 | else 18 | fprintf(1,'\b\b%d',i); 19 | subject = load(strcat(path, 's', num2str(i), '.mat')); 20 | end 21 | 22 | 23 | subjectID = strcat('s', num2str(i)); 24 | %for each trial, populate subject struct inside main database 25 | for v = 1:40 26 | videoID = strcat('v', num2str(v)); 27 | deapData.(subjectID).(videoID).labels = subject.labels(v,:); 28 | %EEg data on channels 1:32, AUX data on channels 33:40 29 | deapData.(subjectID).(videoID).data = ... 30 | struct('eeg', squeeze(subject.data(v,1:32,:)),... 31 | 'other',squeeze(subject.data(v,33:40,:))); 32 | end 33 | end 34 | 35 | % Very slow/ unopenable 36 | %save(strcat(path,'deapData.'), 'deapData', '-v7.3'); 37 | end 38 | 39 | % Access like so: 40 | %EEG.data = deapData.s4.v6.data.eeg 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /freqBands.m: -------------------------------------------------------------------------------- 1 | function [fb] = freqBands(eeg_data, Fs, bands) 2 | %make frequency bands structure save inputs; 3 | fb.t.data = eeg_data; 4 | fb.param.fs = Fs; 5 | fb.bands = bands; 6 | 7 | %get data dimensions 8 | fb.param.ch_num = size(eeg_data,1); 9 | fb.param.N = size(eeg_data,2); 10 | 11 | %compute frequencies for plotting 12 | fb.f.freq = 0:fb.param.fs/fb.param.N:Fs/2; 13 | 14 | %compute raw power sprectral density (psd) 15 | xdft = fft(fb.t.data, fb.param.N, 2); 16 | xdft = xdft(:,1:fb.param.N/2+1); 17 | psdx = (1/(fb.param.fs*fb.param.N)) * abs(xdft).^2; 18 | 19 | %take away mirrored data and save 20 | psdx(:,2:end-1) = 2*psdx(:,2:end-1); 21 | fb.f.psd = psdx; 22 | 23 | 24 | %Get indexes for frequency band cutoffs 25 | fb.bands.i = fb.bands.freq.*(size(fb.f.psd,2)-1)/(fb.param.fs/2); 26 | fb.f.pbc = zeros(fb.param.ch_num,size(fb.bands.names,2)); 27 | 28 | for band = 1:size(fb.bands.i,1) 29 | %Get indexes of interest 30 | name = char(fb.bands.names(band)); 31 | i1 = fb.bands.i(band,1); 32 | i2 = fb.bands.i(band,2); 33 | %number of points used in calculation 34 | point_num = abs(i2 - i1); 35 | 36 | %compute mid freq for each band (plotting) 37 | fb.bands.med(band) = i1 + (i2-i1)/2; 38 | 39 | 40 | %index PSD matrix for right band 41 | band_data = fb.f.psd(:,i1:i2); 42 | 43 | %Calculate average power over band for each channel 44 | fb.f.pbc(:,band) = sum(band_data,2)./point_num; 45 | 46 | %Calculate average power over all channels 47 | fb.f.pb_tot(band) = sum(fb.f.pbc(:,band))/fb.param.ch_num; 48 | 49 | end 50 | 51 | end -------------------------------------------------------------------------------- /ClassifySVM.m: -------------------------------------------------------------------------------- 1 | %% Classify SVM 2 | SubjectID = 1; 3 | avgFeaturesPerSubject = dimensionReductionAverage(featureData); 4 | features = squeeze(avgFeaturesPerSubject(SubjectID,:,:)); 5 | 6 | labels = getLabels(deapData); 7 | labels = squeeze(labels(SubjectID,:,:)); 8 | 9 | 10 | %% Normalize 11 | temp = bsxfun(@minus,features,mean(features)); 12 | norm_features = bsxfun(@rdivide,temp,std(features)); 13 | % Optional normalize to 1 14 | % norm_features = normc(features); 15 | 16 | %% Binarize Labels for SVM classification 17 | labels = labels > 5; 18 | 19 | %% Split data for testing and classification 20 | training_size = 30; 21 | n = size(norm_features,1); 22 | train_data = norm_features(1:training_size,:); 23 | test_data = norm_features(training_size+1:end,:); 24 | 25 | train_labels = labels(1:training_size,:); 26 | test_labels = labels(training_size+1:end,:); 27 | %% Classify Valence 28 | SVMModelValence = fitcsvm(train_data, train_labels(:,1),'KernelFunction','rbf','Standardize',true); 29 | [predicted_labels_train,scores] = predict(SVMModelValence, train_data); 30 | [predicted_labels,scores] = predict(SVMModelValence, test_data); 31 | 32 | %% 33 | SVMModelValence = fitcsvm(features, labels(:,1),'KernelFunction','rbf','Standardize',true,'CrossVal','on','KFold',10); 34 | indGenError = kfoldLoss(SVMModelValence,'mode','individual') 35 | avgGeneralizationError = kfoldLoss(SVMModelValence) 36 | 37 | %CVSVMModelValence = crossval(SVMModelValence); 38 | %[predicted_labels_train,scores] = predict(CVSVMModelValence, train_data); 39 | %[predicted_labels,scores] = predict(SVMModelValence, test_data); 40 | 41 | %% Classify Valence 42 | -------------------------------------------------------------------------------- /ClassifySVM.asv: -------------------------------------------------------------------------------- 1 | %% Classify SVM 2 | SubjectID = 1; 3 | avgFeaturesPerSubject = dimensionReductionAverage(featureData); 4 | features = squeeze(avgFeaturesPerSubject(SubjectID,:,:)); 5 | 6 | labels = getLabels(deapData); 7 | labels = squeeze(labels(SubjectID,:,:)); 8 | 9 | 10 | %% Normalize 11 | temp = bsxfun(@minus,features,mean(features)); 12 | norm_features = bsxfun(@rdivide,temp,std(features)); 13 | % Optional normalize to 1 14 | % norm_features = normc(features); 15 | 16 | %% Binarize Labels for SVM classification 17 | labels = labels > 5; 18 | 19 | %% Split data for testing and classification 20 | training_size = 30; 21 | n = size(norm_features,1); 22 | train_data = norm_features(1:training_size,:); 23 | test_data = norm_features(training_size+1:end,:); 24 | 25 | train_labels = labels(1:training_size,:); 26 | test_labels = labels(training_size+1:end,:); 27 | %% Classify Valence 28 | SVMModelValence = fitcsvm(train_data, train_labels(:,1),'KernelFunction','rbf','Standardize',true); 29 | [predicted_labels_train,scores] = predict(SVMModelValence, train_data); 30 | [predicted_labels,scores] = predict(SVMModelValence, test_data); 31 | 32 | %% 33 | SVMModelValence = fitcsvm(features, labels(:,1),'KernelFunction','rbf','Standardize',false,'CrossVal','on','KFold',10); 34 | indGenError = kfoldLoss(SVMModelValence,'mode','individual') 35 | avgGeneralizationError = kfoldLoss(SVMModelValence) 36 | 37 | %CVSVMModelValence = crossval(SVMModelValence); 38 | %[predicted_labels_train,scores] = predict(CVSVMModelValence, train_data); 39 | %[predicted_labels,scores] = predict(SVMModelValence, test_data); 40 | 41 | %% Classify Valence 42 | -------------------------------------------------------------------------------- /extractFeaturesFromPSD.m: -------------------------------------------------------------------------------- 1 | function [features] = extractFeaturesFromPSD(psdVal, mappings) 2 | % input is a power spectrum density (PSD) array - one value per channel and 3 | % per frequency band 4 | 5 | channelMap = mappings.channels; 6 | assymPairs = mappings.assymPairs; 7 | caudPairs = mappings.caudPairs; 8 | nChannels = size(psdVal, 1); 9 | nBands = size(psdVal, 2); 10 | nAssymPairs = size(assymPairs,1); 11 | nCaudPairs = size(caudPairs,1); 12 | 13 | features = struct(); 14 | 15 | % 1. power spectral density (PSD) 16 | features.psd = psdVal; 17 | 18 | % 2. differential entropy (DE) 19 | % in a certain band, DE is equivalent to the logarithmic PSD for a 20 | % fixed length EEG sequence. 21 | features.de = log(psdVal); % not sure what base we should use here... 22 | 23 | % 3. differential asymmetry (DASM) 24 | features.dasm = zeros(nAssymPairs, nBands); 25 | for i=1:nAssymPairs 26 | %disp(assymPairs{i,1}) 27 | left = channelMap(assymPairs{i,1}); 28 | right = channelMap(assymPairs{i,2}); 29 | features.dasm(i,:) = features.de(left,:) - features.de(right,:); 30 | end 31 | % 4. rational asymmetry (RASM) 32 | features.rasm = zeros(nAssymPairs, nBands); 33 | for i=1:nAssymPairs 34 | %disp(assymPairs{i,1}) 35 | left = channelMap(assymPairs{i,1}); 36 | right = channelMap(assymPairs{i,2}); 37 | features.rasm(i,:) = features.de(left,:) / features.de(right,:); 38 | end 39 | 40 | % 5. asymmetry (ASM) 41 | features.asm = zeros(nAssymPairs, nBands); 42 | nTotal = nAssymPairs * nBands; 43 | temp = arrayfun(@(x) [features.dasm(x) features.rasm(x)],1:nTotal,'un',0); 44 | temp = cell2mat(temp); 45 | features.asm = reshape(temp,[nAssymPairs,nBands,2]); 46 | 47 | % 6.differential caudality (DCAU) 48 | features.dcau = zeros(nCaudPairs, nBands); 49 | for i=1:nCaudPairs 50 | %disp(caudPairs{i,1}) 51 | front = channelMap(caudPairs{i,1}); 52 | back = channelMap(caudPairs{i,2}); 53 | features.dcau(i,:) = features.de(front,:) - features.de(back,:); 54 | end 55 | 56 | end 57 | --------------------------------------------------------------------------------