Skip to content

Commit c521173

Browse files
committed
included Table with features per epoch and per channel
1 parent 867849b commit c521173

File tree

4 files changed

+84
-19
lines changed

4 files changed

+84
-19
lines changed

CHANGELOG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ in the git logs.
77
### Changed
88
### Removed
99
### Fixed
10+
### Added
11+
12+
13+
## [0.4.4] - 26-08-2020
14+
### Changed
15+
- Returns Table of feature values (per epoch and per channel) from function
16+
`generate_all_features` if input argument `return_feat_epoch=true`
17+
### Removed
18+
### Fixed
1019
- Bug fix for `connectivity_features`; was: if channel labels (cell of strings) are empty
1120
then would assume (incorrectly) only 2 channels and would use index [1,2] for left,right
1221
hemisphere; now: if no channel labels throw warning
@@ -15,8 +24,6 @@ in the git logs.
1524
warning)?
1625

1726

18-
19-
2027
## [0.4.3] - 2020-04-22
2128
### Changed
2229
- changed behaviour for `IBI_burst_prc` and `IBI_burst_number` features: now removing any

connectivity_features/channel_hemisphere_pairs.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
% John M. O' Toole, University College Cork
2323
% Started: 20-04-2016
2424
%
25-
% last update: Time-stamp: <2019-11-06 09:22:54 (otoolej)>
25+
% last update: Time-stamp: <2020-08-26 17:43:45 (otoolej)>
2626
%-------------------------------------------------------------------------------
27-
function ipairs=channel_hemisphere_pairs(channel_labels)
27+
function ipairs=channel_hemisphere_pairs(channel_labels, DBverbose)
28+
if(nargin < 2 || isempty(DBverbose)), DBverbose = false; end
2829

29-
DBverbose=0;
3030

3131
N=length(channel_labels);
3232
[ileft,iright]=channel_hemispheres(channel_labels);

connectivity_features/connectivity_features.m

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
% John M. O' Toole, University College Cork
4141
% Started: 13-04-2016
4242
%
43-
% last update: Time-stamp: <2020-08-17 16:49:56 (otoolej)>
43+
% last update: Time-stamp: <2020-08-26 18:00:41 (otoolej)>
4444
%-------------------------------------------------------------------------------
4545
function featx = connectivity_features(x, Fs, feat_name, params_st, ch_labels)
4646
if(nargin<2), error('need 2 input arguments'); end
@@ -50,12 +50,12 @@
5050

5151

5252
DBplot = 0;
53+
featx = NaN;
5354

5455

5556
[N_channels, N] = size(x);
5657
if(N_channels<2)
57-
featx = NaN;
58-
warning('requires at least 2 channels');
58+
warning('REQUIRED: at least 2 channels for connectivity functions');
5959
return;
6060
end
6161

@@ -81,10 +81,14 @@
8181
[ileft, iright] = channel_hemispheres(ch_labels);
8282
ipairs = channel_hemisphere_pairs(ch_labels);
8383
else
84-
warning('REQUIRED: channel names for coherence function.');
85-
featx = NaN;
84+
warning('REQUIRED: channel names for connectivity functions.');
8685
return;
8786
end
87+
if(isempty(ipairs))
88+
warning('no channel pairs (left / right) for connectivity functions.');
89+
return;
90+
end
91+
8892

8993

9094

generate_all_features.m

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
%
1616
% Outputs:
1717
% feat_st - structure containing features
18-
% feats_per_epoch - cell of features x channel x epoch x frequency_band
18+
% feats_per_epoch - table of features per epoch; in long format, with columns:
19+
% [time - channel - freq. band - value - feature name]
20+
% start_time_sec: start time of the epoch (seconds)
21+
% channel: name of channel (string)
22+
% freq_band: number of frequency band (string, e.g. FB1)
23+
% feature_value: value of the feature (real number, scalar)
24+
% feature: name of the feature (string)
1925
%
2026
%
2127
% Example:
@@ -32,10 +38,10 @@
3238
% John M. O' Toole, University College Cork
3339
% Started: 07-04-2016
3440
%
35-
% last update: Time-stamp: <2020-04-23 16:24:02 (otoolej)>
41+
% last update: Time-stamp: <2020-08-17 18:08:33 (otoolej)>
3642
%-------------------------------------------------------------------------------
37-
function [feat_st,feats_per_epochs]=generate_all_features(fname,channel_names,feat_set, ...
38-
return_feat_epoch)
43+
function [feat_st, feats_all_epochs_tb] = generate_all_features(fname, channel_names, feat_set, ...
44+
return_feat_epoch)
3945
if(nargin<2 || isempty(channel_names)), channel_names=[]; end
4046
if(nargin<3 || isempty(feat_set)), feat_set=[]; end
4147
if(nargin<4 || isempty(return_feat_epoch)), return_feat_epoch = false; end
@@ -102,6 +108,7 @@
102108
end
103109

104110
N_feats=length(feat_set);
111+
feats_all_epochs_tb = [];
105112

106113
% A) iterate over features
107114
for n=1:N_feats
@@ -117,9 +124,9 @@
117124
if( any(strcmp({'amplitude','spectral','rEEG','FD'},feat_group)) )
118125

119126
% B) iterate over channels
120-
feats_channel=[]; x_epochs=[];
127+
feats_channel=[]; x_epochs=[]; feats_tbl = [];
121128
for c=1:N_channels
122-
x_epochs=overlap_epochs(eeg_data(c,:)',Fs,EPOCH_LENGTH,EPOCH_OVERLAP);
129+
[x_epochs, epoch_start_times] = overlap_epochs(eeg_data(c,:)',Fs,EPOCH_LENGTH,EPOCH_OVERLAP);
123130
N_epochs=size(x_epochs,1);
124131

125132
% C) iterate over epochs
@@ -147,14 +154,35 @@
147154
end
148155
% if want to return feature estimated over all epochs:
149156
if(return_feat_epoch)
150-
feats_per_epochs{n}(c,:,:)=feats_epochs;
157+
% feats_per_epochs{n}(c,:,:)=feats_epochs;
158+
159+
% create table with features and start time of epoch:
160+
fb_names = arrayfun(@(x) ['FB' num2str(x)], 1:size(feats_epochs, 2), 'un', false);
161+
tb = array2table([epoch_start_times' feats_epochs], ...
162+
'VariableNames', ['start_time_sec', fb_names]);
163+
% add channel:
164+
tb.channel(:) = string(ch_labels{c});
165+
166+
% convert from wide to long format for frequency bands:
167+
tb = stack(tb, fb_names, 'newDataVariableName', {'feature_value'}, ...
168+
'IndexVariableName', {'freq_band'});
169+
170+
feats_tbl = [feats_tbl; tb];
151171
end
152172

153173
% median over all epochs
154174
feats_channel(c,:)=nanmedian(feats_epochs, 1);
155175
end
156176
% and median over all channels:
157177
feat_st.(char(feat_set{n}))=nanmedian(feats_channel, 1);
178+
179+
180+
if(return_feat_epoch)
181+
% add feature name and combine:
182+
feats_tbl.feature(:) = string(feat_set{n});
183+
feats_all_epochs_tb = [feats_all_epochs_tb; feats_tbl];
184+
end
185+
158186

159187
%---------------------------------------------------------------------
160188
% CONNECTIVITY FEATURES
@@ -164,7 +192,12 @@
164192

165193
x_epochs=[];
166194
for c=1:N_channels
167-
x_epochs(c,:,:)=overlap_epochs(eeg_data(c,:)',Fs,EPOCH_LENGTH,EPOCH_OVERLAP);
195+
if(c == N_channels)
196+
[x_epochs(c,:,:), epoch_start_times] = ...
197+
overlap_epochs(eeg_data(c,:)',Fs,EPOCH_LENGTH,EPOCH_OVERLAP);
198+
else
199+
x_epochs(c,:,:) = overlap_epochs(eeg_data(c,:)',Fs,EPOCH_LENGTH,EPOCH_OVERLAP);
200+
end
168201
end
169202
N_epochs=size(x_epochs,2);
170203

@@ -186,6 +219,25 @@
186219
% median over all epochs
187220
feat_st.(char(feat_set{n}))=nanmedian(feats_epochs, 1);
188221

222+
% if want to return feature estimated over all epochs:
223+
if(return_feat_epoch)
224+
% create table with features and start time of epoch:
225+
fb_names = arrayfun(@(x) ['FB' num2str(x)], 1:size(feats_epochs, 2), 'un', false);
226+
tb = array2table([epoch_start_times' feats_epochs], ...
227+
'VariableNames', ['start_time_sec', fb_names]);
228+
% add channel:
229+
tb.channel(:) = NaN;
230+
231+
% convert from wide to long format for frequency bands:
232+
tb = stack(tb, fb_names, 'newDataVariableName', {'feature_value'}, ...
233+
'IndexVariableName', {'freq_band'});
234+
235+
% add feature name and combine:
236+
tb.feature(:) = string(feat_set{n});
237+
feats_all_epochs_tb = [feats_all_epochs_tb; tb];
238+
end
239+
240+
189241

190242
%---------------------------------------------------------------------
191243
% inter-burst interval features
@@ -208,7 +260,7 @@
208260

209261

210262

211-
function [x_epochs] = overlap_epochs(x, Fs, L_window, overlap, window_type)
263+
function [x_epochs, start_times] = overlap_epochs(x, Fs, L_window, overlap, window_type)
212264
%---------------------------------------------------------------------
213265
% overlapping epochs in one matrix
214266
%---------------------------------------------------------------------
@@ -232,11 +284,13 @@
232284

233285

234286
x_epochs = NaN(N_epochs, L_epoch);
287+
start_times = NaN(1, N_epochs);
235288
for k = 1:N_epochs
236289
nf = nw + (k - 1) * L_hop;
237290
% zero-pad if outside x:
238291
nf = nf(ismember(nf, ix)) + 1;
239292
i_nf = 1:length(nf);
293+
start_times(k) = (min(nf) - 1) / Fs;
240294

241295
x_epochs(k, i_nf) = x(nf) .* win_epoch(i_nf).';
242296
end

0 commit comments

Comments
 (0)