Transient gamma events delineate somatosensory modality in S1.
The 3 matches
- [1] § Results › Transient gamma events correlate with stimulus modality and nocifensive response ↔ spectralevents.py, lines 293–399 · score 0.76 · un normalized TFR, event frequency span, Event onset, suprathreshold regions, maximum power, spectral events
- [2] § Results › Transient gamma events correlate with stimulus modality and nocifensive response ↔ spectralevents_find.m, lines 282–404 · score 0.71 · un normalized TFR, Event onset, suprathreshold regions, maximum power, spectral events, magnitude
- [3] § STAR★Methods › Method details › Spectral event analysis ↔ spectralevents_find.m, lines 203–280 · score 0.68 · spectralEvents, event metrics, un normalized, Shin, frequency bands, peaks
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
MATLAB · 528 lines · 32 KB · BSD-3-Clause · 2 matches
- function specEv_struct = spectralevents_find(findMethod, eventBand, thrFOM, tVec, fVec, TFR, classLabels)
- % SPECTRALEVENTS_FIND Algorithm for finding and calculating spectral
- % events on a trial-by-trial basis of a single subject/session. Uses
- % one of three methods before further analyzing and organizing event
- % features:
- %
- % 1) (Primary event detection method in Shin et al. eLife 2017): Find
- % spectral events by first retrieving all local maxima in
- % un-normalized TFR using imregionalmax, then selecting suprathreshold
- % peaks within the frequency band of interest. This method allows for
- % multiple, overlapping events to occur in a given suprathreshold
- % region and does not guarantee the presence of within-band,
- % suprathreshold activity in any given trial will render an event.
- % 2) Find spectral events by first thresholding
- % entire normalize TFR (over all frequencies), then finding local
- % maxima. Discard those of lesser magnitude in each suprathreshold
- % region, respectively, s.t. only the greatest local maximum in each
- % region survives (when more than one local maxima in a region have
- % the same greatest value, their respective event timing, freq.
- % location, and boundaries at full-width half-max are calculated
- % separately and averaged). This method does not allow for overlapping
- % events to occur in a given suprathreshold region and does not
- % guarantee the presence of within-band, suprathreshold activity in
- % any given trial will render an event.
- % 3) Find spectral events by first thresholding
- % normalized TFR in frequency band of interest, then finding local
- % maxima. Discard those of lesser magnitude in each suprathreshold region,
- % respectively, s.t. only the greatest local maximum in each region
- % survives (when more than one local maxima in a region have the same
- % greatest value, their respective event timing, freq. location, and
- % boundaries at full-width half-max are calculated separately and
- % averaged). This method does not allow for overlapping events to occur in
- % a given suprathreshold region and ensures the presence of
- % within-band, suprathreshold activity in any given trial will render
- % an event.
- %
- % specEv_struct = SPECTRALEVENTS_FIND(findMethod,eventBand,thrFOM,tVec,fVec,TFR,classLabels)
- %
- % Inputs:
- % findMethod - integer value specifying which event-finding method to use
- % (1, 2, or 3). Note that the method specifies how much overlap
- % exists between events. Use 1 to replicate the method used in
- % et al. eLife 2017.
- % eventBand - range of frequencies ([Fmin_event Fmax_event]; Hz) over
- % which above-threshold spectral power events are classified.
- % thrFOM - factors of median threshold; positive real number used to
- % threshold local maxima and classify events (see Shin et al. eLife
- % 2017 for discussion concerning this value).
- % tVec - time vector (s) over which the time-frequency response (TFR) is
- % calcuated.
- % fVec - frequency vector (Hz) over which the time-frequency response
- % (TFR) is calcuated.
- % TFR - time-frequency response (TFR) (frequency-by-time-trial) for a
- % single subject/session.
- % classLabels - numeric or logical 1-row array of trial classification
- % labels; associates each trial of the given subject/session to an
- % experimental condition/outcome/state (e.g., hit or miss, detect or
- % non-detect, attend-to or attend away).
- %
- % Outputs:
- % specEv_struct - event feature structure with three main sub-structures:
- % TrialSummary (trial-level features), Events (individual event
- % characteristics), and IEI (inter-event intervals from all trials
- % and those associated with only a given class label).
- %
- % See also SPECTRALEVENTS, SPECTRALEVENTS_FIND, SPECTRALEVENTS_TS2TFR, SPECTRALEVENTS_VIS.
- % Initialize general data parameters
- eventBand_inds = fVec>=eventBand(1) & fVec<=eventBand(2); %Logical vector representing indices of freq vector within eventBand
- if size(eventBand_inds,1)~=length(eventBand_inds)
- eventBand_inds = eventBand_inds'; %Transpose so that the dimensions correspond with the frequency-domain dimension of the TFR
- end
- flength = size(TFR,1); %Number of elements in discrete frequency spectrum
- tlength = size(TFR,2); %Number of points in time
- numTrials = size(TFR,3); %Number of trials
- classes = unique(classLabels);
- medianpower = median(reshape(TFR, size(TFR,1), size(TFR,2)*size(TFR,3)), 2); %Median power at each frequency across all trials
- thr = thrFOM*medianpower; %Spectral event threshold for each frequency value
- % Validate consistency of parameter dimensions
- if flength~=length(fVec) || tlength~=length(tVec) || numTrials~=length(classLabels)
- error('Mismatch in input parameter dimensions!')
- end
- % Find events using the method-of-choice
- spectralEvents = []; %Array for storing event results
- switch findMethod
- case 1
- find_localmax_method_1;
- case 2
- find_localmax_method_2;
- case 3
- find_localmax_method_3;
- otherwise
- error('Unknown event-finding method.')
- end
- % Make sure this subject/session contains >1 events
- if isempty(spectralEvents)
- disp('Warning!! This subject/session contains no events!!')
- specEv_struct = struct('TrialSummary',[],'Events',[],'IEI',[]);
- return;
- end
- % Identify and organize event features
- % Matrix of event features: each row is an event
- % 11 column matrix with 1. trial index, 2. hit/miss, 3. maxima frequency, 4. lowerbound frequency, 5. upperbound frequency, 6. frequency span, ...
- % 7. maxima timing, 8. event onset timing, 9. event offset timing, 10. event duration, 11. maxima power, 12. maxima/median power
- spectralEvents_columnlabel={'trialind', 'classLabels', 'maximafreq', 'lowerboundFspan', 'upperboundFspan', 'Fspan', ...
- 'maximatiming', 'onsettiming', 'offsettiming', 'duration', 'maximapower', 'maximapowerFOM'};
- for rci=1:numel(spectralEvents_columnlabel)
- eventsind.(spectralEvents_columnlabel{rci})=rci;
- end
- trialSummary.classLabels = classLabels';
- trialSummary.meanpower = mean(squeeze(mean(TFR(eventBand_inds,:,:),2)) ./ repmat(medianpower(eventBand_inds),1,numTrials), 1)'; %Mean trial power normalized to frequency-specific median
- suprathrTFR = TFR>=repmat(thr,1,tlength,numTrials);
- trialSummary.coverage = squeeze(sum(sum(suprathrTFR(eventBand_inds,:,:),1),2)) *100 / (nnz(eventBand_inds)*tlength); %Calculated in percentage
- % Initialize column vectors
- trialSummary.eventnumber = nan(numTrials,1);
- trialSummary.meaneventpower = nan(numTrials,1);
- trialSummary.meaneventduration = nan(numTrials,1);
- trialSummary.meaneventFspan = nan(numTrials,1);
- trialSummary.mostrecenteventtiming = nan(numTrials,1);
- trialSummary.mostrecenteventpower = nan(numTrials,1);
- trialSummary.mostrecenteventduration = nan(numTrials,1);
- trialSummary.mostrecenteventFspan = nan(numTrials,1);
- % Iterate through trials
- for tri=1:numTrials
- trialSummary.eventnumber(tri)=nnz(spectralEvents(:,1)==tri);
- if nnz(spectralEvents(:,1)==tri)==0
- trialSummary.meaneventpower(tri) = 0; % traces2TFR always returns a positive value
- trialSummary.meaneventduration(tri) = 0;
- trialSummary.meaneventFspan(tri) = 0;
- trialSummary.mostrecenteventtiming(tri) = tVec(1)-mean(diff(tVec));
- trialSummary.mostrecenteventpower(tri) = 0;
- trialSummary.mostrecenteventduration(tri) = 0;
- trialSummary.mostrecenteventFspan(tri) = 0;
- else
- trialSummary.meaneventpower(tri) = mean(spectralEvents(spectralEvents(:,eventsind.trialind)==tri,eventsind.maximapowerFOM)); % traces2TFR always returns a positive value
- trialSummary.meaneventduration(tri) = mean(spectralEvents(spectralEvents(:,eventsind.trialind)==tri,eventsind.duration));
- trialSummary.meaneventFspan(tri) = mean(spectralEvents(spectralEvents(:,eventsind.trialind)==tri,eventsind.Fspan));
- trialSummary.mostrecenteventtiming(tri) = spectralEvents(find(spectralEvents(:,eventsind.trialind)==tri,1,'last'), eventsind.maximatiming);
- trialSummary.mostrecenteventpower(tri) = spectralEvents(find(spectralEvents(:,eventsind.trialind)==tri,1,'last'), eventsind.maximapowerFOM);
- trialSummary.mostrecenteventduration(tri) = spectralEvents(find(spectralEvents(:,eventsind.trialind)==tri,1,'last'), eventsind.duration);
- trialSummary.mostrecenteventFspan(tri) = spectralEvents(find(spectralEvents(:,eventsind.trialind)==tri,1,'last'), eventsind.Fspan);
- end
- end
- % Event dependent features (mean power, mean length, most recent timing):
- % need special treatment for zero event trials
- specialFeat.field = {'meaneventpower','meaneventduration','meaneventFspan','mostrecenteventtiming',...
- 'mostrecenteventpower','mostrecenteventduration','mostrecenteventFspan'};
- % Percent change from mean (PCM)
- trialSum_featNames = fieldnames(trialSummary);
- for feat_i=2:numel(trialSum_featNames)
- pcm_name = [trialSum_featNames{feat_i},'_pcm'];
- feature = trialSummary.(trialSum_featNames{feat_i});
- % Control for features that need special treatment
- validtrials = trialSummary.eventnumber>0 ; %Trials that do have events
- if ismember(trialSum_featNames{feat_i},specialFeat.field)
- trialSummary.(pcm_name) = 100 * (feature-mean(feature(validtrials))) ./ repmat(abs(mean(feature(validtrials))),numTrials,1);
- else
- trialSummary.(pcm_name) = 100 * (feature-mean(feature))./repmat(abs(mean(feature)),numTrials,1);
- end
- end
- % Inter-event interval (IEI)
- ieitemp=diff(spectralEvents(:,eventsind.maximatiming));
- sametrial=(diff(spectralEvents(:,eventsind.trialind))==0);
- IEI.IEI_all = ieitemp(sametrial);
- for cls_i=1:numel(classes)
- fieldName = ['IEI_',num2str(classes(cls_i))];
- iei_class=diff(spectralEvents(spectralEvents(:,eventsind.classLabels)==classes(cls_i),eventsind.maximatiming));
- sametrial_class=(diff(spectralEvents(spectralEvents(:,eventsind.classLabels)==classes(cls_i),eventsind.trialind)) == 0);
- IEI.(fieldName) = iei_class(sametrial_class);
- end
- % Assign output structure with 3 main branches: trial-level summary
- % (TrialSummary), trial-specific events (Events), and mean inter-event
- % interval across trials (IEI)
- specEv_struct.TrialSummary = struct('NumTrials',numTrials,'SpecialFeatures',specialFeat,'TrialSummary',trialSummary);
- specEv_struct.Events = struct('EventBand',eventBand,'ThrFOM',thrFOM,'MedianPower',medianpower,'Threshold',thr,'Events',struct(spectralEvents_columnlabel{1},spectralEvents(:,1),...
- spectralEvents_columnlabel{2},spectralEvents(:,2),spectralEvents_columnlabel{3},spectralEvents(:,3),spectralEvents_columnlabel{4},spectralEvents(:,4),...
- spectralEvents_columnlabel{5},spectralEvents(:,5),spectralEvents_columnlabel{6},spectralEvents(:,6),spectralEvents_columnlabel{7},spectralEvents(:,7),...
- spectralEvents_columnlabel{8},spectralEvents(:,8),spectralEvents_columnlabel{9},spectralEvents(:,9),spectralEvents_columnlabel{10},spectralEvents(:,10),...
- spectralEvents_columnlabel{11},spectralEvents(:,11),spectralEvents_columnlabel{12},spectralEvents(:,12)));
- specEv_struct.IEI = IEI;
- function find_localmax_method_1
- % 1st event-finding method (primary event detection method in Shin et
- % al. eLife 2017): Find spectral events by first retrieving all local
- % maxima in un-normalized TFR using imregionalmax, then selecting
- % suprathreshold peaks within the frequency band of interest. This
- % method allows for multiple, overlapping events to occur in a given
- % suprathreshold region and does not guarantee the presence of
- % within-band, suprathreshold activity in any given trial will render
- % an event.
- % spectralEvents: 12 column matrix for storing local max event metrics: trial
- % index, hit/miss, maxima frequency, lowerbound frequency, upperbound
- % frequency, frequency span, maxima timing, event onset timing, event
- % offset timing, event duration, maxima power, maxima/median power
- spectralEvents = [];
- % Finds_localmax: stores peak frequecy at each local max (columns) for each
- % trial (rows)
- Finds_localmax = [];
- % Retrieve all local maxima in TFR using imregionalmax
- for ti=1:numTrials
- [peakF,peakT] = find(imregionalmax(squeeze(TFR(:,:,ti)))); %Indices of max local power
- peakpower = TFR(find(imregionalmax(squeeze(TFR(:,:,ti))))+(ti-1)*flength*tlength); %Power values at local maxima (vector; compiles across frequencies and time)
- % Find local maxima lowerbound, upperbound, and full width at half max
- % for both frequency and time
- Ffwhm = NaN(numel(peakpower),3); %2D matrix for freq-dimension event metrics with columns containing lowerbound, upperbound, and fwhm, respectively
- Tfwhm = NaN(numel(peakpower),3); %2D matrix for time-dimension event metrics with columns containing lowerbound, upperbound, and fwhm, respectively
- for lmi=1:numel(peakpower)
- lmF_underthr = find(squeeze(TFR(:,peakT(lmi),ti) < peakpower(lmi)/2)); %Indices of TFR frequencies of < half max power at the time of a given local peak
- if ~isempty(find(lmF_underthr < peakF(lmi), 1)) && ~isempty(find(lmF_underthr > peakF(lmi), 1))
- Ffwhm(lmi,1) = fVec(lmF_underthr(find(lmF_underthr < peakF(lmi),1,'last'))+1);
- Ffwhm(lmi,2) = fVec(lmF_underthr(find(lmF_underthr > peakF(lmi),1,'first'))-1);
- Ffwhm(lmi,3) = Ffwhm(lmi,2)-Ffwhm(lmi,1)+ min(diff(fVec));
- elseif isempty(find(lmF_underthr < peakF(lmi),1)) && ~isempty(find(lmF_underthr > peakF(lmi),1))
- Ffwhm(lmi,1) = fVec(1);
- Ffwhm(lmi,2) = fVec(lmF_underthr(find(lmF_underthr > peakF(lmi),1,'first'))-1);
- Ffwhm(lmi,3) = 2*(Ffwhm(lmi,2)-fVec(peakF(lmi)))+ min(diff(fVec));
- elseif ~isempty(find(lmF_underthr < peakF(lmi),1)) && isempty(find(lmF_underthr > peakF(lmi),1))
- Ffwhm(lmi,1) = fVec(lmF_underthr(find(lmF_underthr < peakF(lmi),1,'last'))+1);
- Ffwhm(lmi,2) = fVec(end);
- Ffwhm(lmi,3) = 2*(fVec(peakF(lmi))-Ffwhm(lmi,1))+ min(diff(fVec));
- else
- Ffwhm(lmi,1) = fVec(1);
- Ffwhm(lmi,2) = fVec(end);
- Ffwhm(lmi,3) = 2*(fVec(end)-fVec(1)+min(diff(fVec)));
- end
- lmT_underthr = find(squeeze(TFR(peakF(lmi),:,ti) < peakpower(lmi)/2)); %Indices of TFR times of < half max power at the freq of a given local peak
- if ~isempty(find(lmT_underthr < peakT(lmi), 1)) && ~isempty(find(lmT_underthr > peakT(lmi), 1))
- Tfwhm(lmi,1) = tVec(lmT_underthr(find(lmT_underthr < peakT(lmi),1,'last'))+1);
- Tfwhm(lmi,2) = tVec(lmT_underthr(find(lmT_underthr > peakT(lmi),1,'first'))-1);
- Tfwhm(lmi,3) = Tfwhm(lmi,2)-Tfwhm(lmi,1)+ min(diff(tVec));
- elseif isempty(find(lmT_underthr < peakT(lmi),1)) && ~isempty(find(lmT_underthr > peakT(lmi),1))
- Tfwhm(lmi,1) = tVec(1);
- Tfwhm(lmi,2) = tVec(lmT_underthr(find(lmT_underthr > peakT(lmi),1,'first'))-1);
- Tfwhm(lmi,3) = 2*(Tfwhm(lmi,2)-tVec(peakT(lmi)))+ min(diff(tVec));
- elseif ~isempty(find(lmT_underthr < peakT(lmi),1)) && isempty(find(lmT_underthr > peakT(lmi),1))
- Tfwhm(lmi,1) = tVec(lmT_underthr(find(lmT_underthr < peakT(lmi),1,'last'))+1);
- Tfwhm(lmi,2) = tVec(end);
- Tfwhm(lmi,3) = 2*(tVec(peakT(lmi))-Tfwhm(lmi,1))+ min(diff(tVec));
- else
- Tfwhm(lmi,1) = tVec(1);
- Tfwhm(lmi,2) = tVec(end);
- Tfwhm(lmi,3) = 2*(tVec(end)-tVec(1)+min(diff(tVec)));
- end
- end
- % 12 column matrix with 1. trial index, 2. trial class, 3. maxima frequency, 4. lowerbound frequency, 5. upperbound frequency, 6. frequency span, ...
- % 7. maxima timing, 8. event onset timing, 9. event offset timing, 10. event duration, 11. maxima power, 12. maxima/median power, ...
- spectralEvents = [spectralEvents; ti*ones(size(peakF)) classLabels(ti)*ones(size(peakF)) fVec(peakF)' Ffwhm tVec(peakT)' Tfwhm peakpower peakpower./medianpower(peakF)];
- Finds_localmax = [Finds_localmax; peakF];
- end
- % Pick out maxima above threshold and within the frequency band of interest
- spectralEvents = spectralEvents((spectralEvents(:,3)>=eventBand(1) & spectralEvents(:,3)<=eventBand(2) & spectralEvents(:,11)>=thr(Finds_localmax)),:); %Select local maxima
- end
- function find_localmax_method_2
- % 2nd event-finding method: Find spectral events by first thresholding
- % entire normalize TFR (over all frequencies), then finding local
- % maxima. This method does not allow for overlapping events to occur in
- % a given suprathreshold region and does not guarantee the presence of
- % within-band, suprathreshold activity in any given trial will render
- % an event.
- % spectralEvents: 12 column matrix for storing local max event metrics: trial
- % index, hit/miss, maxima frequency, lowerbound frequency, upperbound
- % frequency, frequency span, maxima timing, event onset timing, event
- % offset timing, event duration, maxima power, maxima/median power
- spectralEvents = [];
- % Retrieve local maxima in normalized TFR using imregionalmax,
- % discard those of lesser (un-normalized) magnitude in each suprathreshold
- % region, respectively, and characterize event boundaries (at half max)
- for ti=1:numTrials
- TFR_ST = squeeze(TFR(:,:,ti))./medianpower; %Suprathreshold TFR: first isolate 2D TFR matrix and normalize
- TFR_ST(TFR_ST<thrFOM) = 0; %Set infrathreshold values to zero
- % Find all local maxima in suprathreshold TFR
- TFR_LM = TFR_ST.*imregionalmax(TFR_ST); %Threshold TFR at each respective local maximum
- numTotalPeaks = nnz(TFR_LM);
- % Escape this iteration when this trial contains no suprathreshold
- % local maxima
- if numTotalPeaks==0
- continue
- end
- % Find max peak in each respective suprathreshold region
- [~,regions,numReg,~] = bwboundaries(TFR_ST>=thrFOM); %Separate suprathreshold regions
- evPeakF = cell(1,numReg);
- evPeakT = cell(1,numReg);
- evPeakpower = nan(numReg,1);
- for reg_i=1:numReg
- region = zeros(size(TFR_ST)); %Initialize a blank image that will contain a single region
- region(regions==reg_i) = 1; %Set elements (pixels) in region to the value 1
- TFR_reg = TFR_LM.*region; %Regional local maxima
- [peakF_reg,peakT_reg] = find(TFR_reg); %Indices of regional local maxima
- peakpower_reg = TFR(find(TFR_reg)+(ti-1)*flength*tlength); %Power values at regional local maxima
- maxPeakpower = max(peakpower_reg);
- maxPeak_inds = find(peakpower_reg==maxPeakpower); %Indices of all instances where local maxima have the max peak power
- evPeakF{reg_i} = peakF_reg(maxPeak_inds); %Select TFR indices at max regional peak
- evPeakT{reg_i} = peakT_reg(maxPeak_inds); %Select TFR indices at max regional peak
- evPeakpower(reg_i) = maxPeakpower(1);
- end
- % Find local maxima lowerbound, upperbound, and full width at half max
- % for both frequency and time
- evBndsF = nan(numReg,3);
- evBndsT = nan(numReg,3);
- evPeakF_inds = nan(numReg,1);
- evPeakT_inds = nan(numReg,1);
- evPeakpower_norm = nan(numReg,1);
- for reg_i=1:numReg
- numRegPeaks = numel(evPeakF{reg_i});
- peakF = evPeakF{reg_i};
- peakT = evPeakT{reg_i};
- peakpower = evPeakpower(reg_i);
- Ffwhm = nan(numRegPeaks,3); %2D matrix for freq-dimension event metrics with columns containing lowerbound, upperbound, and fwhm, respectively
- Tfwhm = nan(numRegPeaks,3); %2D matrix for time-dimension event metrics with columns containing lowerbound, upperbound, and fwhm, respectively
- peakpower_norm = nan(numRegPeaks,1); %Vector for storing the normalized power at each regional peak
- for lmi=1:numRegPeaks
- lmF_underthr = find(squeeze(TFR(:,peakT(lmi),ti) < peakpower/2)); %Indices of TFR frequencies of < half max power at the time of a given local peak
- if ~isempty(find(lmF_underthr < peakF(lmi), 1)) && ~isempty(find(lmF_underthr > peakF(lmi), 1))
- Ffwhm(lmi,1) = fVec(lmF_underthr(find(lmF_underthr < peakF(lmi),1,'last'))+1);
- Ffwhm(lmi,2) = fVec(lmF_underthr(find(lmF_underthr > peakF(lmi),1,'first'))-1);
- Ffwhm(lmi,3) = Ffwhm(lmi,2)-Ffwhm(lmi,1)+ min(diff(fVec));
- elseif isempty(find(lmF_underthr < peakF(lmi),1)) && ~isempty(find(lmF_underthr > peakF(lmi),1))
- Ffwhm(lmi,1) = fVec(1);
- Ffwhm(lmi,2) = fVec(lmF_underthr(find(lmF_underthr > peakF(lmi),1,'first'))-1);
- Ffwhm(lmi,3) = 2*(Ffwhm(lmi,2)-fVec(peakF(lmi)))+ min(diff(fVec));
- elseif ~isempty(find(lmF_underthr < peakF(lmi),1)) && isempty(find(lmF_underthr > peakF(lmi),1))
- Ffwhm(lmi,1) = fVec(lmF_underthr(find(lmF_underthr < peakF(lmi),1,'last'))+1);
- Ffwhm(lmi,2) = fVec(end);
- Ffwhm(lmi,3) = 2*(fVec(peakF(lmi))-Ffwhm(lmi,1))+ min(diff(fVec));
- else
- Ffwhm(lmi,1) = fVec(1);
- Ffwhm(lmi,2) = fVec(end);
- Ffwhm(lmi,3) = 2*(fVec(end)-fVec(1)+min(diff(fVec)));
- end
- lmT_underthr = find(squeeze(TFR(peakF(lmi),:,ti) < peakpower/2)); %Indices of TFR times of < half max power at the freq of a given local peak
- if ~isempty(find(lmT_underthr < peakT(lmi), 1)) && ~isempty(find(lmT_underthr > peakT(lmi), 1))
- Tfwhm(lmi,1) = tVec(lmT_underthr(find(lmT_underthr < peakT(lmi),1,'last'))+1);
- Tfwhm(lmi,2) = tVec(lmT_underthr(find(lmT_underthr > peakT(lmi),1,'first'))-1);
- Tfwhm(lmi,3) = Tfwhm(lmi,2)-Tfwhm(lmi,1)+ min(diff(tVec));
- elseif isempty(find(lmT_underthr < peakT(lmi),1)) && ~isempty(find(lmT_underthr > peakT(lmi),1))
- Tfwhm(lmi,1) = tVec(1);
- Tfwhm(lmi,2) = tVec(lmT_underthr(find(lmT_underthr > peakT(lmi),1,'first'))-1);
- Tfwhm(lmi,3) = 2*(Tfwhm(lmi,2)-tVec(peakT(lmi)))+ min(diff(tVec));
- elseif ~isempty(find(lmT_underthr < peakT(lmi),1)) && isempty(find(lmT_underthr > peakT(lmi),1))
- Tfwhm(lmi,1) = tVec(lmT_underthr(find(lmT_underthr < peakT(lmi),1,'last'))+1);
- Tfwhm(lmi,2) = tVec(end);
- Tfwhm(lmi,3) = 2*(tVec(peakT(lmi))-Tfwhm(lmi,1))+ min(diff(tVec));
- else
- Tfwhm(lmi,1) = tVec(1);
- Tfwhm(lmi,2) = tVec(end);
- Tfwhm(lmi,3) = 2*(tVec(end)-tVec(1)+min(diff(tVec)));
- end
- peakpower_norm(lmi) = TFR_ST(peakF(lmi),peakT(lmi));
- end
- evBndsF(reg_i,:) = mean(Ffwhm,1);
- evBndsT(reg_i,:) = mean(Tfwhm,1);
- evPeakF_inds(reg_i) = round(mean(peakF));
- evPeakT_inds(reg_i) = round(mean(peakT));
- evPeakpower_norm(reg_i) = mean(peakpower_norm);
- end
- % 12 column matrix with 1. trial index, 2. trial class, 3. maxima frequency, 4. lowerbound frequency, 5. upperbound frequency, 6. frequency span, ...
- % 7. maxima timing, 8. event onset timing, 9. event offset timing, 10. event duration, 11. maxima power, 12. maxima/median power, ...
- spectralEvents = [spectralEvents; ti*ones(size(evPeakpower)) classLabels(ti)*ones(size(evPeakpower))...
- fVec(evPeakF_inds)' evBndsF tVec(evPeakT_inds)' evBndsT evPeakpower evPeakpower_norm];
- end
- % Pick out maxima within the frequency band of interest
- spectralEvents = spectralEvents((spectralEvents(:,3)>=eventBand(1) & spectralEvents(:,3)<=eventBand(2)),:); %Select local maxima
- end
- function find_localmax_method_3
- % 3rd event-finding method: Find spectral events by first thresholding
- % normalized TFR in frequency band of interest, then finding local
- % maxima. This method does not allow for overlapping events to occur in
- % a given suprathreshold region and ensures the presence of
- % within-band, suprathreshold activity in any given trial will render
- % an event.
- % spectralEvents: 12 column matrix for storing local max event metrics: trial
- % index, hit/miss, maxima frequency, lowerbound frequency, upperbound
- % frequency, frequency span, maxima timing, event onset timing, event
- % offset timing, event duration, maxima power, maxima/median power
- spectralEvents = [];
- % Retrieve local maxima in normalized TFR using imregionalmax,
- % discard those of lesser (un-normalized) magnitude in each suprathreshold
- % region, respectively, and characterize event boundaries (at half max)
- for ti=1:numTrials
- TFR_ST = squeeze(TFR(:,:,ti))./medianpower; %Suprathreshold TFR: first isolate 2D TFR matrix and normalize
- TFR_ST(TFR_ST<thrFOM) = 0; %Set infrathreshold values to zero
- TFR_ST = TFR_ST.*eventBand_inds; %Set out-of-band values to zero
- % Find all local maxima in suprathreshold TFR
- TFR_LM = TFR_ST.*imregionalmax(TFR_ST); %Threshold TFR at each respective local maximum
- numTotalPeaks = nnz(TFR_LM);
- % Escape this iteration when this trial contains no suprathreshold
- % local maxima
- if numTotalPeaks==0
- continue
- end
- % Find max peak in each respective suprathreshold region
- [~,regions,numReg,~] = bwboundaries(TFR_ST>=thrFOM); %Separate suprathreshold regions
- evPeakF = cell(1,numReg);
- evPeakT = cell(1,numReg);
- evPeakpower = nan(numReg,1);
- for reg_i=1:numReg
- region = zeros(size(TFR_ST)); %Initialize a blank image that will contain a single region
- region(regions==reg_i) = 1; %Set elements (pixels) in region to the value 1
- TFR_reg = TFR_LM.*region; %Regional local maxima
- [peakF_reg,peakT_reg] = find(TFR_reg); %Indices of regional local maxima
- peakpower_reg = TFR(find(TFR_reg)+(ti-1)*flength*tlength); %Power values at regional local maxima
- maxPeakpower = max(peakpower_reg);
- maxPeak_inds = find(peakpower_reg==maxPeakpower); %Indices of all instances where local maxima have the max peak power
- evPeakF{reg_i} = peakF_reg(maxPeak_inds); %Select TFR indices at max regional peak
- evPeakT{reg_i} = peakT_reg(maxPeak_inds); %Select TFR indices at max regional peak
- evPeakpower(reg_i) = maxPeakpower(1);
- end
- % Find local maxima lowerbound, upperbound, and full width at half max
- % for both frequency and time
- evBndsF = nan(numReg,3);
- evBndsT = nan(numReg,3);
- evPeakF_inds = nan(numReg,1);
- evPeakT_inds = nan(numReg,1);
- evPeakpower_norm = nan(numReg,1);
- for reg_i=1:numReg
- numRegPeaks = numel(evPeakF{reg_i});
- peakF = evPeakF{reg_i};
- peakT = evPeakT{reg_i};
- peakpower = evPeakpower(reg_i);
- Ffwhm = nan(numRegPeaks,3); %2D matrix for freq-dimension event metrics with columns containing lowerbound, upperbound, and fwhm, respectively
- Tfwhm = nan(numRegPeaks,3); %2D matrix for time-dimension event metrics with columns containing lowerbound, upperbound, and fwhm, respectively
- peakpower_norm = nan(numRegPeaks,1); %Vector for storing the normalized power at each regional peak
- for lmi=1:numRegPeaks
- lmF_underthr = find(squeeze(TFR(:,peakT(lmi),ti) < peakpower/2)); %Indices of TFR frequencies of < half max power at the time of a given local peak
- if ~isempty(find(lmF_underthr < peakF(lmi), 1)) && ~isempty(find(lmF_underthr > peakF(lmi), 1))
- Ffwhm(lmi,1) = fVec(lmF_underthr(find(lmF_underthr < peakF(lmi),1,'last'))+1);
- Ffwhm(lmi,2) = fVec(lmF_underthr(find(lmF_underthr > peakF(lmi),1,'first'))-1);
- Ffwhm(lmi,3) = Ffwhm(lmi,2)-Ffwhm(lmi,1)+ min(diff(fVec));
- elseif isempty(find(lmF_underthr < peakF(lmi),1)) && ~isempty(find(lmF_underthr > peakF(lmi),1))
- Ffwhm(lmi,1) = fVec(1);
- Ffwhm(lmi,2) = fVec(lmF_underthr(find(lmF_underthr > peakF(lmi),1,'first'))-1);
- Ffwhm(lmi,3) = 2*(Ffwhm(lmi,2)-fVec(peakF(lmi)))+ min(diff(fVec));
- elseif ~isempty(find(lmF_underthr < peakF(lmi),1)) && isempty(find(lmF_underthr > peakF(lmi),1))
- Ffwhm(lmi,1) = fVec(lmF_underthr(find(lmF_underthr < peakF(lmi),1,'last'))+1);
- Ffwhm(lmi,2) = fVec(end);
- Ffwhm(lmi,3) = 2*(fVec(peakF(lmi))-Ffwhm(lmi,1))+ min(diff(fVec));
- else
- Ffwhm(lmi,1) = fVec(1);
- Ffwhm(lmi,2) = fVec(end);
- Ffwhm(lmi,3) = 2*(fVec(end)-fVec(1)+min(diff(fVec)));
- end
- lmT_underthr = find(squeeze(TFR(peakF(lmi),:,ti) < peakpower/2)); %Indices of TFR times of < half max power at the freq of a given local peak
- if ~isempty(find(lmT_underthr < peakT(lmi), 1)) && ~isempty(find(lmT_underthr > peakT(lmi), 1))
- Tfwhm(lmi,1) = tVec(lmT_underthr(find(lmT_underthr < peakT(lmi),1,'last'))+1);
- Tfwhm(lmi,2) = tVec(lmT_underthr(find(lmT_underthr > peakT(lmi),1,'first'))-1);
- Tfwhm(lmi,3) = Tfwhm(lmi,2)-Tfwhm(lmi,1)+ min(diff(tVec));
- elseif isempty(find(lmT_underthr < peakT(lmi),1)) && ~isempty(find(lmT_underthr > peakT(lmi),1))
- Tfwhm(lmi,1) = tVec(1);
- Tfwhm(lmi,2) = tVec(lmT_underthr(find(lmT_underthr > peakT(lmi),1,'first'))-1);
- Tfwhm(lmi,3) = 2*(Tfwhm(lmi,2)-tVec(peakT(lmi)))+ min(diff(tVec));
- elseif ~isempty(find(lmT_underthr < peakT(lmi),1)) && isempty(find(lmT_underthr > peakT(lmi),1))
- Tfwhm(lmi,1) = tVec(lmT_underthr(find(lmT_underthr < peakT(lmi),1,'last'))+1);
- Tfwhm(lmi,2) = tVec(end);
- Tfwhm(lmi,3) = 2*(tVec(peakT(lmi))-Tfwhm(lmi,1))+ min(diff(tVec));
- else
- Tfwhm(lmi,1) = tVec(1);
- Tfwhm(lmi,2) = tVec(end);
- Tfwhm(lmi,3) = 2*(tVec(end)-tVec(1)+min(diff(tVec)));
- end
- peakpower_norm(lmi) = TFR_ST(peakF(lmi),peakT(lmi));
- end
- evBndsF(reg_i,:) = mean(Ffwhm,1);
- evBndsT(reg_i,:) = mean(Tfwhm,1);
- evPeakF_inds(reg_i) = round(mean(peakF));
- evPeakT_inds(reg_i) = round(mean(peakT));
- evPeakpower_norm(reg_i) = mean(peakpower_norm);
- end
- % 12 column matrix with 1. trial index, 2. trial class, 3. maxima frequency, 4. lowerbound frequency, 5. upperbound frequency, 6. frequency span, ...
- % 7. maxima timing, 8. event onset timing, 9. event offset timing, 10. event duration, 11. maxima power, 12. maxima/median power, ...
- spectralEvents = [spectralEvents; ti*ones(size(evPeakpower)) classLabels(ti)*ones(size(evPeakpower))...
- fVec(evPeakF_inds)' evBndsF tVec(evPeakT_inds)' evBndsT evPeakpower evPeakpower_norm];
- end
- end
- end
spectralevents_find.m at commit cd0c83d, under BSD-3-Clause · at the source
Overview
- School of Engineering, Brown University, Providence, RI 02912, USA
- Biomedical Engineering, Lerner Research Institute, Cleveland Clinic, Cleveland, OH 44195, USA
- Carney Institute for Brain Science, Brown University, Providence, RI 02912, USA
- Center for Neurorestoration and Neurotechnology, Rehabilitation R&D Service, Department of Veterans Affairs, Providence, RI 02908, USA
Abstract
The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.
Repository
Its files are read in the Code ↔ Paper reader above, with 3 matches between paragraphs and lines of code.
jonescompneurolab/SpectralEvents
cd0c83d2492446e03f1e58b79ed31bc73c024f22, 22 July 2024Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
13 files
- __init__.py, Python, 2 lines
- example.m, MATLAB, 38 lines
- spectralevents.m, MATLAB, 115 lines
- spectralevents.py, Python, 601 lines, 1 match
- spectralevents_find.m, MATLAB, 528 lines, 2 matches
- spectralevents_ts2tfr.m, MATLAB, 73 lines
- spectralevents_vis.m, MATLAB, 245 lines
- tests/
__init__.py , Python, 1 line - tests/
save_matlab_events.m , MATLAB, 23 lines - tests/
test_event_detection.py , Python, 122 lines - tutorial.ipynb, Jupyter, 306 lines
- LICENSE, License, 28 lines
- README.md, Text, 149 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 11 scripts, each with its path and the digest of its content;
- 3 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
Datasets cited
Code and data availability statement
The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:
- it points to a dataset: OSF gu3jr
- it says that the data are available on request
- it says that the code is available on request
Read it in the paper: doi.org/10.1016/j.isci.2026.117355.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 2, 28 September 2026
- Authors: added David A. Borton (0000-0003-0710-3005); removed David A. Borton
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 3 authors, 4 keywords, 3 funders, 46 references, 2 RRIDs.
Cite
This paper
Black, C. J., Saab, C. Y., & Borton, D. A. (2026). Transient gamma events delineate somatosensory modality in S1. iScience, 29(9), 117355. https://
BibTeX
@article{black2026transi
author = {Black, Christopher J. and Saab, Carl Y. and Borton, David A.},
title = {{Transient gamma events delineate somatosensory modality in S1}},
journal = {iScience},
year = {2026},
month = aug,
volume = {29},
number = {9},
pages = {117355},
publisher = {Elsevier},
issn = {2589-0042},
doi = {10.1016/
url = {https://
pmid = {42699307},
pmcid = {PMC13544319}
}
RIS
TY - JOUR
AU - Black, Christopher J.
AU - Saab, Carl Y.
AU - Borton, David A.
TI - Transient gamma events delineate somatosensory modality in S1
T2 - iScience
J2 - iScience
PY - 2026
DA - 2026/
VL - 29
IS - 9
SP - 117355
SN - 2589-0042
PB - Elsevier
DO - 10.1016/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1016/
"type": "article-journal",
"title": "Transient gamma events delineate somatosensory modality in S1",
"container-title": "iScience",
"author": [
{
"family": "Black",
"given": "Christopher J."
},
{
"family": "Saab",
"given": "Carl Y."
},
{
"family": "Borton",
"given": "David A."
}
],
"container-title-short":
"volume": "29",
"issue": "9",
"page": "117355",
"DOI": "10.1016/
"PMID": "42699307",
"PMCID": "PMC13544319",
"ISSN": "2589-0042",
"publisher": "Elsevier",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
26
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1097/j.pain.0000000000004044 [code]
- No effect of rhythmic visual stimulation on experimental pain perception.Journal: PainIn common: SciPy, Matplotlib, NumPy, 4 references
- [2] doi:10.1016/j.isci.2026.116152 [code]
- Integrating multidimensional nociceptive-related cortical features for unsupervised assessment of anesthesia states in rats.Journal: iScienceIn common: 5 references
- [3] doi:10.3390/bioengineering13070793
- Vibrotactile Stimulation Encoded by Beta and Gamma Bands Varies with Locations on the Upper Limbs.Journal: Bioengineering (Basel, Switzerland)In common: 3 references
- [4] doi:10.1371/journal.pcbi.1014378 [code]
- A mean-field model of neural networks with PV and SOM interneurons reveals connectivity-based mechanisms of gamma oscillations.Journal: PLoS computational biologyIn common: SciPy, Matplotlib, NumPy, 2 references
- [5] doi:10.1093/braincomms/fcag145 [code]
- GABA&
lt;sub& gt;A& lt;/ sub& gt; binding correlates with high-frequency EEG: a possible proxy for depolarization in traumatic brain injury. Journal: Brain communicationsIn common: SciPy, Matplotlib, NumPy, 2 references - [6] doi:10.1016/j.celrep.2026.117845 [code]
- Hippocampal skill memory expansion drives online performance dynamics during skill learning.Journal: Cell reportsIn common: Image Processing Toolbox, SciPy, Matplotlib, 1 other tool, 1 reference
- [7] doi:10.1162/imag.a.1229 [code]
- 40 Hz audiovisual stimulation improves sustained attention and related brain oscillations.Journal: Imaging neuroscience (Cambridge, Mass.)In common: Image Processing Toolbox, SciPy, Matplotlib, 1 other tool, 1 reference
- [8] doi:10.1371/journal.pbio.3003824 [code]
- Flexible goal learning involves coordinated population activity in dCA1 and medial orbitofrontal cortex.Journal: PLoS biologyIn common: SciPy, Matplotlib, NumPy, systems, 1 reference
- [9] doi:10.7554/elife.108408 [code]
- Frequency and laminar profile of feature-specific visual activity revealed by interleaved EEG-fMRI.Journal: eLifeIn common: Image Processing Toolbox, SciPy, Matplotlib, 1 other tool, systems
- [10] doi:10.1016/j.isci.2026.117375 [code]
- Motor priming is associated with widespread recruitment into neural ensembles and more rapid ensemble transitions.Journal: iScienceIn common: Image Processing Toolbox, SciPy, Matplotlib, 1 other tool, systems
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 11 scripts, and 3 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:733ef8ac7f8646e7…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
