Chromatic_Integration_Contrast_Order.m 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. function varargout = Chromatic_Integration_Contrast_Order(pulsenumbers, varargin)
  2. %
  3. %
  4. %%% Chromatic_Integration_Contrast_Order %%%
  5. %
  6. %
  7. % This function returns the stimulus order and contrast values for the defined
  8. % numbers of input pluses. It uses Fisher-Yates random permutation to set the
  9. % stimulus order. For more info, see the function fisher_Yates_shuffle_order
  10. % below.
  11. %
  12. % ===============================Inputs====================================
  13. %
  14. % pulsenumbers : number of stimulus pulses.
  15. %
  16. % =========================Optional Inputs=================================
  17. %
  18. % selecttextfile false Browse prompt to select the parameters text file
  19. % stimduration 30 Stimulus presentation duration screen refresh rate unit (30 = 0.5 sec)
  20. % preframes 120 Duration of background light presented in between the stimulus flashes
  21. % maxcontrast 0.2 Maximum Weber contrast value (ranges from -1 to 1)
  22. % mincontrast -0.2 Minimum Weber contrast value (ranges from -1 to 1)
  23. % contrastdiff 0.02 Contrast steps from mincontrast to maxcontrast e.g. -20 : 2 : 20
  24. % seed -1000 Starting value for random number generator (should be always negative)
  25. % redmeanintensity 0 Mean intensity for red gun of the screen
  26. % greenmeanintensity 0.5 Mean intensity for green gun of the screen
  27. % bluemeanintensity 0.5 Mean intensity for blue gun of the screen
  28. % help false Option to check the list of available parameters
  29. %
  30. %================================Output====================================
  31. %
  32. % varargout{1} : stimulus order, green contrasts and blue contrasts.
  33. % varargout{2} : stimulus order.
  34. %
  35. % written by Mohammad, 12.02.2021
  36. para = read_stimulus_parameters(varargin{:});
  37. if para.help, return; end
  38. offcontrasts = fliplr(0:-para.contrastdiff:para.mincontrast);
  39. oncontrasts = 0:para.contrastdiff:para.maxcontrast;
  40. numcontrasts = length(oncontrasts)*2;
  41. % generating contrast values
  42. if numel(pulsenumbers) > 1
  43. para.numtrials = floor( length( pulsenumbers(2 : 2 : numel(pulsenumbers))) / numcontrasts );
  44. else
  45. para.numtrials = floor( pulsenumbers/2 / numcontrasts ); % 1 pulse for stimulus, one for preframe
  46. end
  47. seed = para.seed;
  48. stimorder = nan(para.numtrials, numcontrasts);
  49. % getting the order and location of each contrast from the psudo random sequence
  50. for ii = 1 : para.numtrials
  51. [stimorder(ii,:),seed,~] = fisher_Yates_shuffle_order(seed, 1:numcontrasts);
  52. end
  53. % setting up output to get the stimulus order contrast orders
  54. stimorder = stimorder'; % transposing to make vectorization (:) easier
  55. stimorder = stimorder(:);
  56. % out.numberContrastsShown = floor((framecounter-1)/(para.stimduration+para.preframes));
  57. % stimorder = stimorder(1:out.numberContrastsShown);
  58. out.stimulusOrder = transpose(stimorder);
  59. % to get contrasts between input values
  60. greencontrasts = [offcontrasts,oncontrasts];
  61. bluecontrasts = [oncontrasts,offcontrasts];
  62. % convert to weber contrast (mean+(contrast*mean))
  63. greencontrasts = para.greenmeanintensity + (greencontrasts * para.greenmeanintensity);
  64. bluecontrasts = para.bluemeanintensity + (bluecontrasts * para.bluemeanintensity);
  65. % set the contrast output
  66. out.greenContrasts = greencontrasts(stimorder);
  67. out.blueContrasts = bluecontrasts(stimorder);
  68. out.trialnumbers = para.numtrials;
  69. varargout{1} = out;
  70. varargout{2} = stimorder;
  71. end
  72. %--------------------------------------------------------------------------------------------------%
  73. %---------- sub-functions ----------%
  74. %--------------------------------------------------------------------------------------------------%
  75. function varargout = fisher_Yates_shuffle_order(seed,inputVec,varargin)
  76. %
  77. %%% fisher_Yates_shuffle_order %%%
  78. %
  79. %
  80. % This function generate psudorandom permution similar to randperm in MATLAB
  81. % but works with psudorandom number generator ran1. It also gives back the
  82. % most recent seed value to continue the permuation in case of repeated trials.
  83. % note that the direction of permutation is along x-axix or for columns of
  84. % MATALB not for the rows.
  85. %
  86. %
  87. % ===============================Inputs====================================
  88. %
  89. % seed : seed value for random number generation.
  90. % inputVec : input vector used for permutation.
  91. %
  92. %================================Output====================================
  93. %
  94. % testOrder : vector of permuted indices for the inputVec.
  95. % newSeed : the recent seed that used in the ran1 function.
  96. % outputVec : the permuted input vector along x-axis
  97. %
  98. % Note that the permution algorithem is based on Fisher-Yates shuffle
  99. % algorithem identical to what is used in the stimulus program.
  100. % for more info check :
  101. % https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
  102. %
  103. % written by Mohammad, 01.02.2016
  104. newSeed = seed;
  105. testOrder = zeros(1,size(inputVec,2));
  106. testOrder(1) = 1;
  107. for i = 2:length(inputVec)-1
  108. [randVal,newSeed] = ran1(newSeed);
  109. j = ceil(i*randVal); % based on Fischer-Yates algorithem
  110. testOrder(i) = testOrder(j);
  111. testOrder(j) = i;
  112. end
  113. testOrder = [testOrder(end),testOrder(1:end-1)]+1; % to match MATLAB indexing
  114. varargout{1} = testOrder;
  115. varargout{2} = newSeed;
  116. for j = 1:size(inputVec,1)
  117. varargout{3}(j,:) = inputVec(j,testOrder);
  118. end
  119. end
  120. %--------------------------------------------------------------------------------------------------%
  121. function paraout = read_stimulus_parameters(varargin)
  122. % first parse the user inputs
  123. p = inputParser(); % check the user options.
  124. p.addParameter('selecttextfile', false, @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1])));
  125. p.addParameter('stimduration', 30, @isnumeric);
  126. p.addParameter('preframes', 120, @isnumeric);
  127. p.addParameter('contrastdiff', 0.02, @isnumeric);
  128. p.addParameter('mincontrast',-0.2, @isnumeric);
  129. p.addParameter('maxcontrast', 0.2, @isnumeric);
  130. p.addParameter('seed', -1000, @isnumeric);
  131. p.addParameter('redmeanintensity', 0, @isnumeric);
  132. p.addParameter('greenmeanintensity', 0.5, @isnumeric);
  133. p.addParameter('bluemeanintensity', 0.5, @isnumeric);
  134. p.addParameter('help', false, @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1])));
  135. p.parse(varargin{:});
  136. % defualt parameters
  137. defpara = p.Results;
  138. if defpara.help
  139. help_info_for_parameters(defpara);
  140. paraout = defpara;
  141. return;
  142. end
  143. if defpara.selecttextfile
  144. % now read the text files
  145. [stimfile, stimpath] = uigetfile('*.txt','Select a chromatic integration stimulus parameter file','chromatic_integration.txt');
  146. fid = fopen([stimpath,filesep,stimfile]);
  147. tline = fgetl(fid);
  148. while ischar(tline)
  149. tline = fgetl(fid);
  150. if tline == -1, break; end
  151. fn = extractBefore(tline,' = ');
  152. if isempty(fn), continue; end
  153. val = extractAfter(tline,' = ');
  154. % to convert to double
  155. if ~isnan(str2double(val))
  156. val = str2double(val);
  157. end
  158. % to convert to logical
  159. if strcmp(val,'true'), val = true; end
  160. if strcmp(val,'false'), val = false; end
  161. % store the values in a structure
  162. stimpara.(fn) = val;
  163. end
  164. fclose(fid);
  165. % compare the text file to the defualt values and fill the missing parameters
  166. fn = fieldnames(defpara);
  167. for ii = 1:numel(fn)
  168. if isfield(stimpara,fn{ii})
  169. paraout.(fn{ii}) = stimpara.(fn{ii});
  170. else
  171. paraout.(fn{ii}) = defpara.(fn{ii});
  172. end
  173. end
  174. else
  175. paraout = defpara;
  176. end
  177. end
  178. %--------------------------------------------------------------------------------------------------%
  179. function help_info_for_parameters(defpara)
  180. fn = fieldnames(defpara);
  181. fprintf(['\n\n',repmat('==',1,50),'\r\n']);
  182. fprintf([repmat(' ',1,35),'List of Stimulus Parameters\r\n']);
  183. fprintf([repmat('==',1,50),'\r\n']);
  184. maxtxtlen = max(cellfun(@numel,fn))+10;
  185. for ii = 1:numel(fn)
  186. g = repmat(' ',1,maxtxtlen - numel(fn{ii}));
  187. fprintf(['\t-- \t%s',g,':',repmat(' ',1,10),'%s\n'],fn{ii},num2str(defpara.(fn{ii})));
  188. end
  189. fprintf(['\n',repmat('==',1,50),'\r\n']);
  190. end