Skip to content
Merged
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
11 changes: 10 additions & 1 deletion src/pspm_cfg/pspm_cfg_help_format.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
% GUI
% Format: helptext = pspm_cfg_help_format(funcname, [argname])
% helptext = pspm_cfg_help_format('import', helptext)
% helptext = pspm_cfg_help_format('pspm_pupil_pp_options', outputname)
% funcname: PsPM function name (char)
% argname: function argument (potentially a chain of nested
% struct fields, e.g. 'options.overwrite')
% outputname: output argument (potentially a chain of nested
% struct fields)

global settings

if nargin < 2
Expand Down Expand Up @@ -35,8 +39,13 @@
A = strrep(argname, newline, [newline, newline]);
helptext = splitlines(A);
else
if strcmpi(funcname, 'pspm_pupil_pp_options')
fieldtype = 'Outputs';
else
fieldtype = 'Arguments';
end
% this syntax allows chaining several nested structs into one argname
evalc(sprintf('helptext = settings.help.%s.Arguments.%s;', funcname, argname));
evalc(sprintf('helptext = settings.help.%s.%s.%s;', funcname, fieldtype, argname));
% remove entries in square brackets
[startindx, endindx] = regexp(helptext, '\[\s*([^\[\]]*)\s*\]'); % thanks ChatGPT for finding the regexp
for k = numel(startindx):-1:1
Expand Down
29 changes: 11 additions & 18 deletions src/pspm_cfg/pspm_cfg_process_illuminance.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,62 +25,55 @@
sr.tag = 'sr';
sr.strtype = 'i';
sr.num = [1 1];
sr.help = {'Specify the sample rate of the illuminance data.'};
sr.help = pspm_cfg_help_format('pspm_process_illuminance', 'sr');
%% Duration
duration = cfg_entry;
duration.name = 'Duration';
duration.tag = 'duration';
duration.strtype= 'r';
duration.val = {20};
duration.num = [1 1];
duration.help = {['Specify the duration of the basis function ', ...
'in seconds (default: 20s).']};
duration.help = pspm_cfg_help_format('pspm_process_illuminance', 'options.bf.duration');
%% Offset
offset = cfg_entry;
offset.name = 'Offset';
offset.tag = 'offset';
offset.strtype = 'r';
offset.val = {0.2};
offset.num = [1 1];
offset.help = {['Specify an offset of the basis function in ', ...
'seconds (default: 0.2s).']};
offset.help = pspm_cfg_help_format('pspm_process_illuminance', 'options.bf.offset');
%% LDRF_GM
ldrf_gm = cfg_const;
ldrf_gm.name = 'LDRF_GM';
ldrf_gm.name = 'pspm_bf_ldrf_gm';
ldrf_gm.tag = 'ldrf_gm';
ldrf_gm.val = {true};
ldrf_gm.help = {['Use gamma probability density function to ', ...
'model the dilation response (default).']};
ldrf_gm.help = {'Gamma probability density function.'};
%% LDRF_GU
ldrf_gu = cfg_const;
ldrf_gu.name = 'LDRF_GU';
ldrf_gu.name = 'pspm_bf_ldrf_gu';
ldrf_gu.tag = 'ldrf_gu';
ldrf_gu.val = {true};
ldrf_gu.help = {['Use a smoothed gaussian function to model ', ...
'the dilation response.']};
ldrf_gu.help = {'Smoothed Gaussian.'};
%% Dilation
dilation = cfg_choice;
dilation.name = 'Dilation';
dilation.tag = 'dilation';
dilation.values = {ldrf_gm, ldrf_gu};
dilation.val = {ldrf_gm};
dilation.help = {['Specify the basis function to model the ', ...
'dilation response.']};
dilation.help = pspm_cfg_help_format('pspm_process_illuminance', 'options.bf.dilation');
%% LCRF_GM
lcrf_gm = cfg_const;
lcrf_gm.name = 'LCRF_GM';
lcrf_gm.name = 'pspm_bf_lcrf_gm';
lcrf_gm.tag = 'lcrf_gm';
lcrf_gm.val = {true};
lcrf_gm.help = {['Use gamma probability density function to model ', ...
'the constriction response (default).']};
lcrf_gm.help = {};
%% Constriction
constrict = cfg_choice;
constrict.name = 'Constriction';
constrict.tag = 'constriction';
constrict.val = {lcrf_gm};
constrict.values= {lcrf_gm};
constrict.help = {['Specify the basis function to model the ', ...
'constriction response.']};
constrict.help = pspm_cfg_help_format('pspm_process_illuminance', 'options.bf.constriction');
%% Basis function options
bf = cfg_branch;
bf.name = 'Basis function options';
Expand Down
94 changes: 40 additions & 54 deletions src/pspm_cfg/pspm_cfg_pupil_preprocess.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,133 +32,121 @@
PupilDiameterMin.tag = 'PupilDiameter_Min';
PupilDiameterMin.num = [1 1];
PupilDiameterMin.val = {1.5};
PupilDiameterMin.help = {'Minimum allowed pupil diameter in ',...
'the same unit as the pupil channel.'};
PupilDiameterMin.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.PupilDiameter_Min');

% Pupil diameter maximum
PupilDiameterMax = cfg_entry;
PupilDiameterMax.name = 'Maximum allowed pupil diameter';
PupilDiameterMax.tag = 'PupilDiameter_Max';
PupilDiameterMax.num = [1 1];
PupilDiameterMax.val = {9.0};
PupilDiameterMax.help = {'Maximum allowed pupil diameter in ',...
'the same unit as the pupil channel.'};
PupilDiameterMax.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.PupilDiameter_Max');

% Island filter separation
IslandFiltSeparation = cfg_entry;
IslandFiltSeparation.name = 'Island separation min distance (ms)';
IslandFiltSeparation.tag = 'islandFilter_islandSeparation_ms';
IslandFiltSeparation.num = [1 1];
IslandFiltSeparation.val = {40};
IslandFiltSeparation.help = {'Minimum distance used to consider ',...
'samples ''separated'''};
IslandFiltSeparation.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.islandFilter_islandSeperation_ms');

% Minimum valid island width in millisecond
IslandFiltMinWidth = cfg_entry;
IslandFiltMinWidth.name = 'Min valid island width (ms)';
IslandFiltMinWidth.tag = 'islandFilter_minIslandwidth_ms';
IslandFiltMinWidth.num = [1 1];
IslandFiltMinWidth.val = {50};
IslandFiltMinWidth.help = {['Minimum temporal width required to ',...
'still consider a sample island ',...
'valid. If the temporal width of the ',...
'island is less than this value, all the ',...
'samples in the island will be marked ',...
'as invalid.']};
IslandFiltMinWidth.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.islandFilter_minIslandWidth_ms');

% Dilation speed filter median multiplier
DilationSpdFiltMedMp = cfg_entry;
DilationSpdFiltMedMp.name = 'Number of medians in speed filter';
DilationSpdFiltMedMp.tag = 'dilationSpeedFilter_MadMultiplier';
DilationSpdFiltMedMp.num = [1 1];
DilationSpdFiltMedMp.val = {16};
DilationSpdFiltMedMp.help = {'Number of median to use as the cutoff ',...
'threshold when applying the speed filter'};
DilationSpdFiltMedMp.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.dilationSpeedFilter_MadMultiplier');

% Dilation speed filter maximum gap in millisecond
DilationSpdFiltMaxGap = cfg_entry;
DilationSpdFiltMaxGap.name = 'Max gap to compute speed (ms)';
DilationSpdFiltMaxGap.tag = 'dilationSpeedFilter_maxGap_ms';
DilationSpdFiltMaxGap.num = [1 1];
DilationSpdFiltMaxGap.val = {200};
DilationSpdFiltMaxGap.help = {'Only calculate the speed when the gap ',...
'between samples is smaller than this value.'};
DilationSpdFiltMaxGap.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.dilationSpeedFilter_maxGap_ms');

% Gap detect minimum width in millisecond
GapDetectMinWidth = cfg_entry;
GapDetectMinWidth.name = 'Min missing data width (ms)';
GapDetectMinWidth.tag = 'gapDetect_minWidth';
GapDetectMinWidth.num = [1 1];
GapDetectMinWidth.val = {75};
GapDetectMinWidth.help = {'Minimum width of a missing data section ',...
'that causes it to be classified as a gap.'};
GapDetectMinWidth.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.gapDetect_minWidth');

% Gap detect maximum width in millisecond
GapDetectMaxWidth = cfg_entry;
GapDetectMaxWidth.name = 'Max missing data width (ms)';
GapDetectMaxWidth.tag = 'gapDetect_maxWidth';
GapDetectMaxWidth.num = [1 1];
GapDetectMaxWidth.val = {2000};
GapDetectMaxWidth.help = {'Maximum width of a missing data section ',...
'that causes it to be classified as a gap.'};
GapDetectMaxWidth.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.gapDetect_maxWidth');

% Gap padding backword
GapPaddingBwd = cfg_entry;
GapPaddingBwd.name = 'Reject before missing data (ms)';
GapPaddingBwd.tag = 'gapPadding_backward';
GapPaddingBwd.num = [1 1];
GapPaddingBwd.val = {50};
GapPaddingBwd.help = {'The section right before the start of a ',...
'gap within which samples are to be rejected.'};
GapPaddingBwd.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.gapPadding_backward');

% Gap padding forward
GapPaddingFwd = cfg_entry;
GapPaddingFwd.name = 'Reject after missing data (ms)';
GapPaddingFwd.tag = 'gapPadding_forward';
GapPaddingFwd.num = [1 1];
GapPaddingFwd.val = {50};
GapPaddingFwd.help = {'The section right after the end of a gap ',...
'within which samples are to be rejected.'};
GapPaddingFwd.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.gapPadding_forward');

% Residual filter passes
ResdFiltPass = cfg_entry;
ResdFiltPass.name = 'Deviation filter passes';
ResdFiltPass.tag = 'residualsFilter_passes';
ResdFiltPass.num = [1 1];
ResdFiltPass.val = {4};
ResdFiltPass.help = {'Number of passes deviation filter makes'};
ResdFiltPass.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.residualsFilter_passes');

% Residual filter median multiplier
ResdFiltMedMp = cfg_entry;
ResdFiltMedMp.name = 'Number of medians in deviation filter';
ResdFiltMedMp.tag = 'residualsFilter_MadMultiplier';
ResdFiltMedMp.num = [1 1];
ResdFiltMedMp.val = {16};
ResdFiltMedMp.help = {['The multiplier used when defining the ',...
'threshold. Threshold equals this ',...
'multiplier times the median. After ',...
'each pass, all the input samples that ',...
'are outside the threshold are removed. ',...
'Please note that all samples (even the ',...
'ones which may have been rejected by ',...
'the previous devation filter pass) are ',...
'considered.']};
ResdFiltMedMp.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.residualsFilter_MadMultiplier');

% Residual filter interpolation sampling frequency
ResdFiltInterpFs = cfg_entry;
ResdFiltInterpFs.name = 'Butterworth sampling frequency (Hz)';
ResdFiltInterpFs.tag = 'residualsFilter_interpFs';
ResdFiltInterpFs.num = [1 1];
ResdFiltInterpFs.val = {100};
ResdFiltInterpFs.help = {'Sampling frequency for first order ',...
'Butterworth filter.'};
ResdFiltInterpFs.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.residualsFilter_interpFs');

% Residual filter for lowpass cut-off
ResdFiltLPCF = cfg_entry;
ResdFiltLPCF.name = 'Butterworth cutoff frequency (Hz)';
ResdFiltLPCF.tag = 'residualsFilter_interpFs';
ResdFiltLPCF.num = [1 1];
ResdFiltLPCF.val = {100};
ResdFiltLPCF.help = {'Cutoff frequency for first order ',...
'Butterworth filter.'};
ResdFiltLPCF.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.residualsFilter_lowpassCF');

% Keep filter data
KeepFiltData = cfg_menu;
KeepFiltData.name = 'Store intermediate steps';
KeepFiltData.tag = 'keepFilterData';
KeepFiltData.values = {true, false};
KeepFiltData.labels = {'True', 'False'};
KeepFiltData.val = {false};
KeepFiltData.help = {['If true, intermediate filter data will ',...
'be stored for plotting. ',...
'Set to false to save memory and improve ',...
'plotting performance.']};
KeepFiltData.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'raw.keepFilterData');

% Raw custom setting
RawCustomSet = cfg_branch;
RawCustomSet.name = 'Settings for raw data preprocessing';
Expand All @@ -185,35 +173,33 @@
InterpUpSampFreq.tag = 'interp_upsamplingFreq';
InterpUpSampFreq.num = [1 1];
InterpUpSampFreq.val = {1000};
InterpUpSampFreq.help = {'The upsampling frequency used to generate ',...
'the smooth signal. (Hz)'};
InterpUpSampFreq.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'valid.interp_maxGap');

% Low pass filter cutoff frequency in Hz
LPFiltCutoffFreq = cfg_entry;
LPFiltCutoffFreq.name = 'Lowpass filter cutoff frequency (Hz)';
LPFiltCutoffFreq.tag = 'LpFilt_cutoffFreq';
LPFiltCutoffFreq.num = [1 1];
LPFiltCutoffFreq.val = {4};
LPFiltCutoffFreq.help = {'Cutoff frequency of the lowpass filter ',...
'used during final smoothing. (Hz)'};
LPFiltCutoffFreq.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'valid.interp_maxGap');

% Low pass filter order
LPFiltOrder = cfg_entry;
LPFiltOrder.name = 'Lowpass filter order';
LPFiltOrder.tag = 'LpFilt_order';
LPFiltOrder.num = [1 1];
LPFiltOrder.val = {4};
LPFiltOrder.help = {'Filter order of the lowpass filter used ',...
'during final smoothing.'};
LPFiltOrder.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'valid.interp_maxGap');


% Interpolation maximum gap in millisecond
InterpMaxGap = cfg_entry;
InterpMaxGap.name = 'Interpolation max gap (ms)';
InterpMaxGap.tag = 'interp_maxGap';
InterpMaxGap.num = [1 1];
InterpMaxGap.val = {250};
InterpMaxGap.help = {['Maximum gap in the used (valid) raw ',...
'samples to interpolate over. ',...
'Sections that were interpolated over ',...
'distances larger than this value will ',...
'be set to NaN. (ms)']};
InterpMaxGap.help = pspm_cfg_help_format('pspm_pupil_pp_options', 'valid.interp_maxGap');

%% Settings
% Settings for valid data preprocessing
ValidCustomSet = cfg_branch;
Expand All @@ -233,7 +219,7 @@
DefaultSet = cfg_const;
DefaultSet.name = 'Default settings';
DefaultSet.tag = 'default_settings';
DefaultSet.val = {};
DefaultSet.val = {struct()};
% Settings
Set = cfg_choice;
Set.name = 'Settings';
Expand Down
6 changes: 3 additions & 3 deletions src/pspm_cfg/pspm_cfg_selector_overwrite.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
overwrite = cfg_menu;
overwrite.name = 'Overwrite Existing File';
overwrite.tag = 'overwrite';
overwrite.val = {0};
overwrite.labels = {'No', 'Yes'};
overwrite.values = {0, 1};
overwrite.val = {2};
overwrite.labels = {'Discard data if file exists', 'Always overwrite', 'Ask user every time a file exists'};
overwrite.values = {0, 1, 2};
overwrite.help = {'Specify whether you want to overwrite an existing file with the same name.'};
16 changes: 8 additions & 8 deletions src/pspm_process_illuminance.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
% [sts, out] = pspm_process_illuminance(ldata, sr, options)
% ● Arguments
% * ldata: Illuminance data as (cell of) 1x1 double or filename.
% * sr: Sample rate in Hz of the input data.
% * sr: Sample rate in Hz of the input illuminance data.
% ┌────────options
% ├────────────.fn: [filename] Ff specified ldata{i,j} will be saved to a file
% │ with filename options.fn{i,j} into the variable 'R'.
Expand All @@ -27,14 +27,14 @@
% ├──────.transfer: Params for the transfer function
% └────────────.bf: Settings for the basis functions, described as following.
% ┌─────options.bf
% ├──.constriction: Options to the constriction response function. It has a field
% │ ".fhandle" that handles to the constriction response function,
% │ and its allowed values are @pspm_bf_lcrf_gm.
% ├──────.dilation: Options for the dilation basis function. It has a field ".fhandle"
% │ that handle to the dilation response function, and its allowed
% ├──.constriction: [struct with field .fhandle] Options for the
% │ constriction response function. Currently
% │ allowed values are @pspm_bf_lcrf_gm.
% ├──────.dilation: [struct with field .fhandle] Options for the
% │ dilation response function. Currently allowed
% │ values are @pspm_bf_ldrf_gm and @pspm_bf_ldrf_gu.
% ├──────.duration: Duration of the basis functions in second.
% └────────.offset: Offset in second.
% ├──────.duration: Duration of the basis functions in seconds.
% └────────.offset: Offset in seconds.
% ● Outputs
% * sts: status
% * out: has same size as ldata and contains either the
Expand Down