0001 function consolidated = bml_sync_consolidate(cfg)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 if istable(cfg)
0026 cfg = struct('roi',cfg);
0027 end
0028 roi = bml_getopt(cfg,'roi');
0029 timetol = bml_getopt(cfg,'timetol',1e-2);
0030 contiguous = bml_getopt(cfg,'contiguous',true);
0031 group = bml_getopt_single(cfg,'group','session_id');
0032 timewarp = bml_getopt(cfg,'timewarp',true);
0033 rowisfile = bml_getopt(cfg,'rowisfile',true);
0034 group_specified = ismember("group",fieldnames(cfg));
0035
0036 REQUIRED_VARS2 = {'folder','name','chantype','filetype'};
0037 if ~all(ismember(REQUIRED_VARS2,roi.Properties.VariableNames))
0038 if rowisfile
0039 error('Variables %s required',strjoin(REQUIRED_VARS2))
0040 else
0041 for i=1:length(REQUIRED_VARS2)
0042 roi.(REQUIRED_VARS2{i})=repmat({'NA'},height(roi),1);
0043 end
0044 end
0045 end
0046
0047 roi = bml_roi_table(roi);
0048
0049
0050
0051
0052
0053 roi.fullfile = fullfile(roi.folder,roi.name);
0054 if ismember(group,roi.Properties.VariableNames)
0055 if group_specified
0056 fprintf("grouping by
0057 end
0058 if isnumeric(roi.(group))
0059 roi.fullfile = strcat(roi.fullfile,'_',num2str(roi.(group)));
0060 else
0061 roi.fullfile = strcat(roi.fullfile,'_',roi.(group));
0062 end
0063 end
0064 roi.sync_id = roi.id;
0065 uff = unique(roi.fullfile);
0066 consolidated = table();
0067
0068
0069 for i_uff=1:length(uff)
0070 i_roi = roi(strcmp(roi.fullfile,uff(i_uff)),:);
0071 if height(i_roi)>1
0072
0073
0074 s = [i_roi.s1; i_roi.s2];
0075 t = [i_roi.t1; i_roi.t2];
0076 if timewarp
0077 p = polyfit(s,t,1);
0078 else
0079 assert(length(unique(i_roi.Fs))==1,"Inconsistent Fs");
0080 p1 = 1/unique(i_roi.Fs);
0081 p = [p1, mean(t-p1*s)];
0082 end
0083 tfit = polyval(p,s);
0084
0085 max_delta_t = max(abs(t - tfit));
0086 if max_delta_t <= timetol
0087 consrow = i_roi(1,:);
0088 consrow.starts = min(i_roi.starts);
0089 consrow.ends = max(i_roi.ends);
0090 consrow.s1 = min(i_roi.s1);
0091 consrow.s2 = max(i_roi.s2);
0092 consrow.t1 = polyval(p,consrow.s1);
0093 consrow.t2 = polyval(p,consrow.s2);
0094 if ismember('warpfactor',i_roi.Properties.VariableNames)
0095 consrow.warpfactor = 1/(consrow.Fs * p(1));
0096 end
0097 i_roi = consrow;
0098 else
0099 error('can''t consolidate within tolerance. Max delta t %f > %f',max_delta_t,timetol)
0100 end
0101 end
0102 consolidated = [consolidated; i_roi];
0103 end
0104
0105 consolidated.id=[];
0106 roi.fullfile=[];
0107 consolidated = bml_roi_table(consolidated);
0108
0109
0110 if contiguous
0111 roi = consolidated;
0112 consolidated = table();
0113 roi.filetype_chantype = strcat(roi.filetype,roi.chantype,num2str(roi.Fs));
0114 ufc = unique(roi.filetype_chantype);
0115 for i_ufc=1:length(ufc)
0116 i_roi = roi(strcmp(roi.filetype_chantype,ufc(i_ufc)),:);
0117 if height(i_roi)>1 && length(unique(i_roi.name))<=1
0118
0119 error('multiple chunks for single file after per file consolidation');
0120 consolidated = bml_roi_table(roi);
0121 return
0122 end
0123
0124 cfg=[];
0125 cfg.criterion = @(x) abs(sum(x.duration)-max(x.ends)+min(x.starts)) < height(x)*timetol;
0126 i_roi_cont = bml_annot_consolidate(cfg,i_roi);
0127
0128 for j=1:height(i_roi_cont)
0129 i_roi_cont_j = i_roi(i_roi.id>=i_roi_cont.id_starts(j) & i_roi.id<=i_roi_cont.id_ends(j),:);
0130
0131 if height(i_roi_cont_j)>1
0132
0133 left_complete = i_roi_cont_j.starts(1)<=i_roi_cont_j.t1(1);
0134 right_complete = i_roi_cont_j.ends(end)>=i_roi_cont_j.t2(end);
0135
0136
0137 cs = cumsum(i_roi_cont_j.s2-i_roi_cont_j.s1) + i_roi_cont_j.s1(1);
0138 cs = cs + (0:(height(i_roi_cont_j)-1))';
0139 cs = [0; cs(1:end-1)];
0140 i_roi_cont_j.raw1 = i_roi_cont_j.s1 + cs;
0141 i_roi_cont_j.raw2 = i_roi_cont_j.s2 + cs;
0142
0143
0144 s = [i_roi_cont_j.raw1; i_roi_cont_j.raw2];
0145 t = [i_roi_cont_j.t1; i_roi_cont_j.t2];
0146
0147 if timewarp
0148 p = polyfit(s,t,1);
0149 else
0150 assert(length(unique(i_roi_cont_j.Fs))==1,"Inconsistent Fs");
0151 p1 = 1/unique(i_roi_cont_j.Fs);
0152 p = [p1, mean(t-p1*s)];
0153 end
0154 tfit = polyval(p,s);
0155
0156 max_delta_t = max(abs(t - tfit));
0157 if max_delta_t <= timetol
0158 i_roi_cont_j.t1 = polyval(p,i_roi_cont_j.raw1);
0159 i_roi_cont_j.t2 = polyval(p,i_roi_cont_j.raw2);
0160 if ismember('warpfactor',i_roi_cont_j.Properties.VariableNames)
0161 i_roi_cont_j.warpfactor = 1 ./ (i_roi_cont_j.Fs .* p(1));
0162 end
0163 else
0164 error('can''t consolidate within tolerance. Max delta t %f > %f',max_delta_t,timetol);
0165 end
0166 i_roi_cont_j.raw1=[];
0167 i_roi_cont_j.raw2=[];
0168
0169
0170 if left_complete
0171 i_roi_cont_j.starts(1) = i_roi_cont_j.t1(1) - 0.5/i_roi_cont_j.Fs(1);
0172 end
0173 for i=1:(height(i_roi_cont_j)-1)
0174 i_roi_cont_j.ends(i) = (i_roi_cont_j.t2(i) + i_roi_cont_j.t1(i+1))/2;
0175 i_roi_cont_j.starts(i+1) = (i_roi_cont_j.t2(i) + i_roi_cont_j.t1(i+1))/2;
0176 end
0177 if right_complete
0178 i_roi_cont_j.ends(1) = i_roi_cont_j.t2(1) + 0.5/i_roi_cont_j.Fs(1);
0179 end
0180
0181 consolidated = [consolidated; i_roi_cont_j];
0182 else
0183 consolidated = [consolidated; i_roi_cont_j];
0184 end
0185 end
0186 end
0187 end
0188
0189 consolidated = bml_roi_table(consolidated);
0190