Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions +exploreFNIRS/+core/Experiment.m
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@

% Build channel labels as cell array
if ~isempty(channels)
chLabels = cellstr(num2str(channels(:)));
chLabels = pf2_base.channelLabels(channels);
else
chLabels = {};
end
Expand Down Expand Up @@ -800,7 +800,7 @@

% Build channel labels as cell array
if ~isempty(channels)
chLabels = cellstr(num2str(channels(:)));
chLabels = pf2_base.channelLabels(channels);
else
chLabels = {};
end
Expand Down
9 changes: 5 additions & 4 deletions +exploreFNIRS/+export/mergeGbyTablesLong.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
% times - Time points to include (default: [] = all)
% exportAux - Include auxiliary data (default: false)
% exportROI - Include ROI-averaged data (default: false)
% channelLabels - Cell array of channel name strings (default: numbers)
% channelLabels - Cell array of channel name strings (default: zero-padded
% numbers from pf2_base.channelLabels)
%
% Outputs:
% mergedTables - Combined table in long format with columns:
Expand Down Expand Up @@ -53,7 +54,7 @@
end

if(nargin<7)
channelLabels=cellstr(num2str(channelIndexes));
channelLabels=pf2_base.channelLabels(channelIndexes);
else
channelLabels=cellstr(channelLabels);
end
Expand Down Expand Up @@ -117,7 +118,7 @@
if(emptyChannelFlag&&exportFNIR)
numCh=size(curBarGA.HbO.data,2);
channelIndexes=1:numCh;
channelLabels=cellstr(num2str(channelIndexes(:)));
channelLabels=pf2_base.channelLabels(channelIndexes);
elseif(exportFNIR)
numCh=length(channelIndexes);
else
Expand Down Expand Up @@ -190,7 +191,7 @@
end

if(exportAux&&isfield(curBarGA,'Aux'))
curAuxFields=fields(curBarGA.Aux);
curAuxFields=fieldnames(curBarGA.Aux);
for aux=1:length(curAuxFields)
curAuxName=curAuxFields{aux};
curAux= curBarGA.Aux.(curAuxName);
Expand Down
9 changes: 5 additions & 4 deletions +exploreFNIRS/+export/mergeGbyTablesWide.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
% times - Time points to include (default: [] = all)
% exportAux - Include auxiliary data (default: false)
% exportROI - Include ROI-averaged data (default: false)
% optodeNames - Cell array of optode/channel names (default: numbers)
% optodeNames - Cell array of optode/channel names (default: zero-padded
% numbers from pf2_base.channelLabels)
%
% Outputs:
% mergedTables - Combined table in wide format with columns:
Expand Down Expand Up @@ -53,7 +54,7 @@
end

if(nargin<7)
optodeNames=num2str(channels);
optodeNames=pf2_base.channelLabels(channels);
else
optodeNames=cellstr(optodeNames);
end
Expand Down Expand Up @@ -106,7 +107,7 @@
if(emptyChannelFlag&&exportFNIR)
numCh=size(curBarGA.HbO.data,2);
channels=1:numCh;
optodeNames=cellstr(num2str(channels(:)));
optodeNames=pf2_base.channelLabels(channels);
elseif(exportFNIR)
numCh=length(channels);
else
Expand Down Expand Up @@ -185,7 +186,7 @@
if(exportAux&&isfield(curBarGA,'Aux'))
%warning('To-do add AUX fields to export wide'); % trouble is syncing up timing between each

curAuxFields=fields(curBarGA.Aux);
curAuxFields=fieldnames(curBarGA.Aux);
for aux=1:length(curAuxFields)
curAuxName=curAuxFields{aux};
curAux= curBarGA.Aux.(curAuxName);
Expand Down
2 changes: 1 addition & 1 deletion +exploreFNIRS/+plot/temporal.m
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@

else
dataTime=data2plot.(bioM).time;
varNames=fields(data2plot.(bioM));
varNames=fieldnames(data2plot.(bioM));
timeIdx=ismember(varNames,'time');
firstVar=find(~timeIdx);
data2plot.(bioM)=data2plot.(bioM).(varNames{firstVar(1)});
Expand Down
15 changes: 9 additions & 6 deletions +pf2/+data/+aux/accelFeatures.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [feat, info] = accelFeatures(x, fs, opts)
function [feat, info] = accelFeatures(x, fs, varargin)
% ACCELFEATURES Derive motion features from a multi-axis accelerometer signal
%
% Computes summary motion features from accelerometer/IMU axes: the vector
Expand Down Expand Up @@ -36,11 +36,14 @@
%
% See also: pf2_base.auxSignalType, pf2.data.auxOnGrid

arguments
x {mustBeNumeric}
fs {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive}
opts.RemoveGravity (1,1) logical = true
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
x = pf2_base.args.check(x, '', '', {@mustBeNumeric}, 'Invalid argument at position 1.');
fs = pf2_base.args.check(fs, '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}, 'Invalid argument at position 2.');
opts = pf2_base.args.parse('accelFeatures', varargin, {}, {
'RemoveGravity', (true), '1,1', 'logical', {}
});
removeGravity = opts.RemoveGravity;

if isrow(x)
Expand Down
21 changes: 12 additions & 9 deletions +pf2/+data/+aux/addFeature.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function data = addFeature(data, name, values, opts)
function data = addFeature(data, name, values, varargin)
% ADDFEATURE Store a derived signal as a typed auxiliary feature
%
% Writes a derived feature (e.g. an HR series from heartRateFrom, RVT from
Expand Down Expand Up @@ -38,14 +38,17 @@
% See also: pf2_base.normalizeAux, pf2.data.aux.heartRateFrom,
% pf2.data.aux.respFeatures, pf2.export.asSNIRF

arguments
data {mustBeA(data, 'struct')}
name {mustBeText}
values {mustBeNumeric}
opts.Time {mustBeNumeric} = []
opts.Unit = ''
opts.VarNames = {}
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
data = pf2_base.args.check(data, '', '', {@(v) mustBeA(v, 'struct')}, 'Invalid argument at position 1.');
name = pf2_base.args.check(name, '', '', {@mustBeText}, 'Invalid argument at position 2.');
values = pf2_base.args.check(values, '', '', {@mustBeNumeric}, 'Invalid argument at position 3.');
opts = pf2_base.args.parse('addFeature', varargin, {}, {
'Time', ([]), '', '', {@mustBeNumeric}
'Unit', (''), '', '', {}
'VarNames', ({}), '', '', {}
});
name = matlab.lang.makeValidName(char(string(name)));

t = opts.Time;
Expand Down
15 changes: 9 additions & 6 deletions +pf2/+data/+aux/edaDecompose.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [tonic, phasic, info] = edaDecompose(x, fs, opts)
function [tonic, phasic, info] = edaDecompose(x, fs, varargin)
% EDADECOMPOSE Split electrodermal activity into tonic and phasic components
%
% Decomposes a galvanic skin response / electrodermal activity (GSR/EDA)
Expand Down Expand Up @@ -40,11 +40,14 @@
%
% See also: pf2_base.auxSignalType, pf2.data.aux.heartRateFrom

arguments
x {mustBeNumeric}
fs {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive}
opts.TonicCutoff {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 0.05
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
x = pf2_base.args.check(x, '', '', {@mustBeNumeric}, 'Invalid argument at position 1.');
fs = pf2_base.args.check(fs, '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}, 'Invalid argument at position 2.');
opts = pf2_base.args.parse('edaDecompose', varargin, {}, {
'TonicCutoff', (0.05), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
});
cutoff = opts.TonicCutoff;

x = x(:);
Expand Down
17 changes: 10 additions & 7 deletions +pf2/+data/+aux/eegBandPower.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [bandPower, info] = eegBandPower(x, fs, opts)
function [bandPower, info] = eegBandPower(x, fs, varargin)
% EEGBANDPOWER Extract canonical EEG band-power feature series
%
% Converts a raw EEG waveform (one or more channels) into per-band power
Expand Down Expand Up @@ -46,12 +46,15 @@
%
% See also: pf2_base.auxSignalType, pf2.data.auxOnGrid

arguments
x {mustBeNumeric}
fs {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive}
opts.Bands = []
opts.SmoothWin {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 1
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
x = pf2_base.args.check(x, '', '', {@mustBeNumeric}, 'Invalid argument at position 1.');
fs = pf2_base.args.check(fs, '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}, 'Invalid argument at position 2.');
opts = pf2_base.args.parse('eegBandPower', varargin, {}, {
'Bands', ([]), '', '', {}
'SmoothWin', (1), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
});
bands = opts.Bands;
smoothWin = opts.SmoothWin;

Expand Down
19 changes: 11 additions & 8 deletions +pf2/+data/+aux/heartRateFrom.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [hr, info] = heartRateFrom(x, fs, opts)
function [hr, info] = heartRateFrom(x, fs, varargin)
% HEARTRATEFROM Derive a heart-rate (bpm) series from a PPG or EKG waveform
%
% Detects cardiac beats in a pulsatile waveform (photoplethysmography or
Expand Down Expand Up @@ -47,13 +47,16 @@
%
% See also: pf2_base.auxSignalType, pf2.data.auxOnGrid, pf2.data.aux.edaDecompose

arguments
x {mustBeNumeric}
fs {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive}
opts.Band {mustBeNumeric} = [0.5 5]
opts.MinBPM {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 30
opts.MaxBPM {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 220
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
x = pf2_base.args.check(x, '', '', {@mustBeNumeric}, 'Invalid argument at position 1.');
fs = pf2_base.args.check(fs, '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}, 'Invalid argument at position 2.');
opts = pf2_base.args.parse('heartRateFrom', varargin, {}, {
'Band', ([0.5 5]), '', '', {@mustBeNumeric}
'MinBPM', (30), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
'MaxBPM', (220), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
});
band = opts.Band;
maxBPM = opts.MaxBPM;

Expand Down
26 changes: 15 additions & 11 deletions +pf2/+data/+aux/hrvFeatures.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [hrv, info] = hrvFeatures(x, fs, opts)
function [hrv, info] = hrvFeatures(x, varargin)
% HRVFEATURES Heart-rate variability metrics from a waveform or beat series
%
% Computes standard time- and frequency-domain HRV metrics, which serve as
Expand Down Expand Up @@ -55,16 +55,20 @@
%
% See also: pf2.data.aux.heartRateFrom, pf2_base.auxSignalType

arguments
x {mustBeNumeric}
fs {mustBeNumeric} = []
opts.Input = 'waveform'
opts.IBIUnit = 'ms'
opts.Band {mustBeNumeric} = [0.5 5]
opts.LFBand {mustBeNumeric} = [0.04 0.15]
opts.HFBand {mustBeNumeric} = [0.15 0.40]
opts.ResampleFs {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 4
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
x = pf2_base.args.check(x, '', '', {@mustBeNumeric}, 'Invalid argument at position 1.');
[fs, opts] = pf2_base.args.parse('hrvFeatures', varargin, {
'fs', ([]), '', '', {@mustBeNumeric}
}, {
'Input', ('waveform'), '', '', {}
'IBIUnit', ('ms'), '', '', {}
'Band', ([0.5 5]), '', '', {@mustBeNumeric}
'LFBand', ([0.04 0.15]), '', '', {@mustBeNumeric}
'HFBand', ([0.15 0.40]), '', '', {@mustBeNumeric}
'ResampleFs', (4), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
});
inputType = lower(char(opts.Input));
ibiUnit = lower(char(opts.IBIUnit));
lfBand = opts.LFBand;
Expand Down
31 changes: 17 additions & 14 deletions +pf2/+data/+aux/hrvSeries.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [series, t] = hrvSeries(signal, fs, opts)
function [series, t] = hrvSeries(signal, fs, varargin)
% HRVSERIES Time-resolved HRV metrics via a sliding window over a waveform
%
% Computes standard HRV metrics in successive overlapping windows of a PPG
Expand Down Expand Up @@ -130,19 +130,22 @@
% pf2.data.aux.addFeature, pf2.data.auxOnGrid,
% pf2.data.slidingWindows

arguments
signal {mustBeNumeric, mustBeNonempty}
fs {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive}
opts.Window {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 60
opts.Step {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = []
opts.Overlap {mustBeNumeric, mustBeScalarOrEmpty} = []
opts.Metric = 'all'
opts.MinBeats {mustBeNumeric, mustBeScalarOrEmpty} = []
opts.Band {mustBeNumeric} = [0.5 5]
opts.LFBand {mustBeNumeric} = [0.04 0.15]
opts.HFBand {mustBeNumeric} = [0.15 0.40]
opts.ResampleFs {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 4
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
signal = pf2_base.args.check(signal, '', '', {@mustBeNumeric, @mustBeNonempty}, 'Invalid argument at position 1.');
fs = pf2_base.args.check(fs, '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}, 'Invalid argument at position 2.');
opts = pf2_base.args.parse('hrvSeries', varargin, {}, {
'Window', (60), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
'Step', ([]), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
'Overlap', ([]), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty}
'Metric', ('all'), '', '', {}
'MinBeats', ([]), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty}
'Band', ([0.5 5]), '', '', {@mustBeNumeric}
'LFBand', ([0.04 0.15]), '', '', {@mustBeNumeric}
'HFBand', ([0.15 0.40]), '', '', {@mustBeNumeric}
'ResampleFs', (4), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
});

winLen = opts.Window;
if isempty(opts.MinBeats)
Expand Down
19 changes: 11 additions & 8 deletions +pf2/+data/+aux/respFeatures.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [feat, info] = respFeatures(x, fs, opts)
function [feat, info] = respFeatures(x, fs, varargin)
% RESPFEATURES Derive respiration rate and RVT from a respiration waveform
%
% Detects breaths in a respiration signal (belt / RIP / derived) and returns
Expand Down Expand Up @@ -53,13 +53,16 @@
%
% See also: pf2.data.aux.heartRateFrom, pf2_base.auxSignalType, pf2.data.auxOnGrid

arguments
x {mustBeNumeric}
fs {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive}
opts.Band {mustBeNumeric} = [0.1 0.5]
opts.MinRate {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 5
opts.MaxRate {mustBeNumeric, mustBeScalarOrEmpty, mustBePositive} = 60
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
x = pf2_base.args.check(x, '', '', {@mustBeNumeric}, 'Invalid argument at position 1.');
fs = pf2_base.args.check(fs, '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}, 'Invalid argument at position 2.');
opts = pf2_base.args.parse('respFeatures', varargin, {}, {
'Band', ([0.1 0.5]), '', '', {@mustBeNumeric}
'MinRate', (5), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
'MaxRate', (60), '', '', {@mustBeNumeric, @mustBeScalarOrEmpty, @mustBePositive}
});
band = opts.Band;
maxRate = opts.MaxRate;

Expand Down
25 changes: 14 additions & 11 deletions +pf2/+data/auxOnGrid.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [vals, info] = auxOnGrid(data, name, opts)
function [vals, info] = auxOnGrid(data, name, varargin)
% AUXONGRID Resample a named auxiliary signal onto a target time base
%
% Returns an auxiliary signal aligned to an arbitrary time grid (the fNIRS
Expand Down Expand Up @@ -50,16 +50,19 @@
%
% See also: pf2_base.normalizeAux, pf2_base.auxSignalType, pf2.data.resample

arguments
data {mustBeA(data, 'struct')}
name {mustBeText}
opts.Time {mustBeNumeric} = []
opts.Channels = []
opts.Method = 'linear'
opts.Offset (1,1) {mustBeNumeric} = 0
opts.AntiAlias (1,1) logical = true
opts.MaxGap (1,1) {mustBeNumeric, mustBePositive} = Inf
end
% Inputs are parsed with pf2_base.args rather than an arguments block so
% the function also runs under GNU Octave. Spec rows are {name, default,
% size, class, validators}.
data = pf2_base.args.check(data, '', '', {@(v) mustBeA(v, 'struct')}, 'Invalid argument at position 1.');
name = pf2_base.args.check(name, '', '', {@mustBeText}, 'Invalid argument at position 2.');
opts = pf2_base.args.parse('auxOnGrid', varargin, {}, {
'Time', ([]), '', '', {@mustBeNumeric}
'Channels', ([]), '', '', {}
'Method', ('linear'), '', '', {}
'Offset', (0), '1,1', '', {@mustBeNumeric}
'AntiAlias', (true), '1,1', 'logical', {}
'MaxGap', (Inf), '1,1', '', {@mustBeNumeric, @mustBePositive}
});

name = char(string(name));
method = char(string(opts.Method));
Expand Down
Loading
Loading