function varargout = Chromatic_Integration_Contrast_Order(pulsenumbers, varargin) % % %%% Chromatic_Integration_Contrast_Order %%% % % % This function returns the stimulus order and contrast values for the defined % numbers of input pluses. It uses Fisher-Yates random permutation to set the % stimulus order. For more info, see the function fisher_Yates_shuffle_order % below. % % ===============================Inputs==================================== % % pulsenumbers : number of stimulus pulses. % % =========================Optional Inputs================================= % % selecttextfile false Browse prompt to select the parameters text file % stimduration 30 Stimulus presentation duration screen refresh rate unit (30 = 0.5 sec) % preframes 120 Duration of background light presented in between the stimulus flashes % maxcontrast 0.2 Maximum Weber contrast value (ranges from -1 to 1) % mincontrast -0.2 Minimum Weber contrast value (ranges from -1 to 1) % contrastdiff 0.02 Contrast steps from mincontrast to maxcontrast e.g. -20 : 2 : 20 % seed -1000 Starting value for random number generator (should be always negative) % redmeanintensity 0 Mean intensity for red gun of the screen % greenmeanintensity 0.5 Mean intensity for green gun of the screen % bluemeanintensity 0.5 Mean intensity for blue gun of the screen % help false Option to check the list of available parameters % %================================Output==================================== % % varargout{1} : stimulus order, green contrasts and blue contrasts. % varargout{2} : stimulus order. % % written by Mohammad, 12.02.2021 para = read_stimulus_parameters(varargin{:}); if para.help, return; end offcontrasts = fliplr(0:-para.contrastdiff:para.mincontrast); oncontrasts = 0:para.contrastdiff:para.maxcontrast; numcontrasts = length(oncontrasts)*2; % generating contrast values if numel(pulsenumbers) > 1 para.numtrials = floor( length( pulsenumbers(2 : 2 : numel(pulsenumbers))) / numcontrasts ); else para.numtrials = floor( pulsenumbers/2 / numcontrasts ); % 1 pulse for stimulus, one for preframe end seed = para.seed; stimorder = nan(para.numtrials, numcontrasts); % getting the order and location of each contrast from the psudo random sequence for ii = 1 : para.numtrials [stimorder(ii,:),seed,~] = fisher_Yates_shuffle_order(seed, 1:numcontrasts); end % setting up output to get the stimulus order contrast orders stimorder = stimorder'; % transposing to make vectorization (:) easier stimorder = stimorder(:); % out.numberContrastsShown = floor((framecounter-1)/(para.stimduration+para.preframes)); % stimorder = stimorder(1:out.numberContrastsShown); out.stimulusOrder = transpose(stimorder); % to get contrasts between input values greencontrasts = [offcontrasts,oncontrasts]; bluecontrasts = [oncontrasts,offcontrasts]; % convert to weber contrast (mean+(contrast*mean)) greencontrasts = para.greenmeanintensity + (greencontrasts * para.greenmeanintensity); bluecontrasts = para.bluemeanintensity + (bluecontrasts * para.bluemeanintensity); % set the contrast output out.greenContrasts = greencontrasts(stimorder); out.blueContrasts = bluecontrasts(stimorder); out.trialnumbers = para.numtrials; varargout{1} = out; varargout{2} = stimorder; end %--------------------------------------------------------------------------------------------------% %---------- sub-functions ----------% %--------------------------------------------------------------------------------------------------% function varargout = fisher_Yates_shuffle_order(seed,inputVec,varargin) % %%% fisher_Yates_shuffle_order %%% % % % This function generate psudorandom permution similar to randperm in MATLAB % but works with psudorandom number generator ran1. It also gives back the % most recent seed value to continue the permuation in case of repeated trials. % note that the direction of permutation is along x-axix or for columns of % MATALB not for the rows. % % % ===============================Inputs==================================== % % seed : seed value for random number generation. % inputVec : input vector used for permutation. % %================================Output==================================== % % testOrder : vector of permuted indices for the inputVec. % newSeed : the recent seed that used in the ran1 function. % outputVec : the permuted input vector along x-axis % % Note that the permution algorithem is based on Fisher-Yates shuffle % algorithem identical to what is used in the stimulus program. % for more info check : % https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle % % written by Mohammad, 01.02.2016 newSeed = seed; testOrder = zeros(1,size(inputVec,2)); testOrder(1) = 1; for i = 2:length(inputVec)-1 [randVal,newSeed] = ran1(newSeed); j = ceil(i*randVal); % based on Fischer-Yates algorithem testOrder(i) = testOrder(j); testOrder(j) = i; end testOrder = [testOrder(end),testOrder(1:end-1)]+1; % to match MATLAB indexing varargout{1} = testOrder; varargout{2} = newSeed; for j = 1:size(inputVec,1) varargout{3}(j,:) = inputVec(j,testOrder); end end %--------------------------------------------------------------------------------------------------% function paraout = read_stimulus_parameters(varargin) % first parse the user inputs p = inputParser(); % check the user options. p.addParameter('selecttextfile', false, @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1]))); p.addParameter('stimduration', 30, @isnumeric); p.addParameter('preframes', 120, @isnumeric); p.addParameter('contrastdiff', 0.02, @isnumeric); p.addParameter('mincontrast',-0.2, @isnumeric); p.addParameter('maxcontrast', 0.2, @isnumeric); p.addParameter('seed', -1000, @isnumeric); p.addParameter('redmeanintensity', 0, @isnumeric); p.addParameter('greenmeanintensity', 0.5, @isnumeric); p.addParameter('bluemeanintensity', 0.5, @isnumeric); p.addParameter('help', false, @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1]))); p.parse(varargin{:}); % defualt parameters defpara = p.Results; if defpara.help help_info_for_parameters(defpara); paraout = defpara; return; end if defpara.selecttextfile % now read the text files [stimfile, stimpath] = uigetfile('*.txt','Select a chromatic integration stimulus parameter file','chromatic_integration.txt'); fid = fopen([stimpath,filesep,stimfile]); tline = fgetl(fid); while ischar(tline) tline = fgetl(fid); if tline == -1, break; end fn = extractBefore(tline,' = '); if isempty(fn), continue; end val = extractAfter(tline,' = '); % to convert to double if ~isnan(str2double(val)) val = str2double(val); end % to convert to logical if strcmp(val,'true'), val = true; end if strcmp(val,'false'), val = false; end % store the values in a structure stimpara.(fn) = val; end fclose(fid); % compare the text file to the defualt values and fill the missing parameters fn = fieldnames(defpara); for ii = 1:numel(fn) if isfield(stimpara,fn{ii}) paraout.(fn{ii}) = stimpara.(fn{ii}); else paraout.(fn{ii}) = defpara.(fn{ii}); end end else paraout = defpara; end end %--------------------------------------------------------------------------------------------------% function help_info_for_parameters(defpara) fn = fieldnames(defpara); fprintf(['\n\n',repmat('==',1,50),'\r\n']); fprintf([repmat(' ',1,35),'List of Stimulus Parameters\r\n']); fprintf([repmat('==',1,50),'\r\n']); maxtxtlen = max(cellfun(@numel,fn))+10; for ii = 1:numel(fn) g = repmat(' ',1,maxtxtlen - numel(fn{ii})); fprintf(['\t-- \t%s',g,':',repmat(' ',1,10),'%s\n'],fn{ii},num2str(defpara.(fn{ii}))); end fprintf(['\n',repmat('==',1,50),'\r\n']); end