|
@@ -0,0 +1,245 @@
|
|
|
+
|
|
|
+
|
|
|
+function SpatioTemporal_Binary_White_Noise_Stimulus(varargin)
|
|
|
+%
|
|
|
+%
|
|
|
+%===================================================================================
|
|
|
+% Parameter Default Usage
|
|
|
+%===================================================================================
|
|
|
+%
|
|
|
+% selecttextfile false To call browse prompt to select the parameters text file
|
|
|
+% stixelwidth 6 Width of each pixel of the checkerboard defined in monitor pixels unit
|
|
|
+% stixelheight 6 Height of each pixel of the checkerboard defined in monitor pixels unit
|
|
|
+% blackwhite true Option to switch between Binary and Gaussian white-noise (Not available)
|
|
|
+% contrast 1 Contrast of black & white stimulus. 1 is 100 contrast.
|
|
|
+% meanintensity 0.5 Mean intensity value used to define contrast
|
|
|
+% seed -1000 Starting value for random number generator (should be always negative)
|
|
|
+% secondseed -10000 Same as seed but for green color (only used if color is true).
|
|
|
+% thirdseed -2000 Same as seed but for blue color (only used if color is true).
|
|
|
+% nblinks 2 Number of frames to hold the stimulus on screen (2 is 30 Hz stimulus)
|
|
|
+% color false Option to switch between black & white and chromatic white-noise
|
|
|
+% redmeanintensity 0 Mean intensity for red gun of the screen (only used if color is true).
|
|
|
+% greenmeanintensity 0.5 Mean intensity for green gun of the screen (only used if color is true).
|
|
|
+% bluemeanintensity 0.5 Mean intensity for blue gun of the screen (only used if color is true).
|
|
|
+% redcontrast 0 Contrast of red stimulus (only used if color is true).
|
|
|
+% greencontrast 0.75 Contrast of green stimulus (only used if color is true).
|
|
|
+% bluecontrast 0.75 Contrast of blue stimulus (only used if color is true).
|
|
|
+% screensize 864 x 480 Screen resolution, default value is the resolution of the lightcrafter projector
|
|
|
+% refreshrate 60 Screen refresh rate in Hz
|
|
|
+% fullscreen false Option to display the stimulus in full-screen mode
|
|
|
+% help false Option to check the list of available parameters
|
|
|
+% lmargin 0 Margins from left side of the screen (not available for this stimulus)
|
|
|
+% rmagin 0 Margins from right side of the screen (not available for this stimulus)
|
|
|
+% tmargin 0 Margins from top of the screen (not available for this stimulus)
|
|
|
+% bmargin 0 Margins from bottom of the screen (not available for this stimulus)
|
|
|
+% coneisolating false Option to activate opsin-isolation (excluded for simplicity)
|
|
|
+%
|
|
|
+%====================================================================================
|
|
|
+%
|
|
|
+%
|
|
|
+
|
|
|
+para = read_stimulus_parameters(varargin{:});
|
|
|
+if para.help, return; end
|
|
|
+
|
|
|
+% xax = (para.lmargin+1):para.stixelwidth:(para.screensize(1)-(para.rmargin));
|
|
|
+% yax = (para.bmargin+1):para.stixelheight:(para.screensize(2)-(para.tmargin));
|
|
|
+
|
|
|
+xax = linspace(para.lmargin,para.screensize(1)-(para.rmargin),para.Nx)+para.stixelwidth/2;
|
|
|
+yax = linspace(para.tmargin,para.screensize(2)-(para.bmargin),para.Ny)+para.stixelheight/2;
|
|
|
+
|
|
|
+
|
|
|
+% The darwing of the screen goes here
|
|
|
+monitorsize = get(0,'ScreenSize');
|
|
|
+scpos = [monitorsize(3)/2-(para.screensize(1)/2), ...
|
|
|
+ monitorsize(4)/2-(para.screensize(2)/2), para.screensize];
|
|
|
+% make an screen like figure
|
|
|
+fh = figure('Menu','none','ToolBar','none','Position',scpos,'Color',0.5*[1 1 1]);
|
|
|
+fh.Name = 'Example of Spatio-temporal White Noise Stimulus, from Khani and Gollisch (2021)';
|
|
|
+fh.Colormap = gray;
|
|
|
+ah = axes('Units','Normalize','Position',[0 0 1 1],'Color',0.5*[1 1 1]);
|
|
|
+axis(ah,[0, para.screensize(1),0, para.screensize(2)]);
|
|
|
+axis(ah,'off');
|
|
|
+
|
|
|
+
|
|
|
+framecounter = 0;
|
|
|
+if para.color
|
|
|
+ seed1 = para.seed;
|
|
|
+ seed2 = para.secondseed;
|
|
|
+ seed3 = para.thirdseed;
|
|
|
+
|
|
|
+ redWeberContrastHigh = para.redmeanintensity + (para.redContrast * para.redmeanintensity);
|
|
|
+ redWeberContrastLow = para.redmeanintensity - (para.redContrast * para.redmeanintensity);
|
|
|
+ greenWeberContrastHigh = para.greenmeanintensity + (para.greenContrast * para.greenmeanintensity);
|
|
|
+ greenWeberContrastLow = para.greenmeanintensity - (para.greenContrast * para.greenmeanintensity);
|
|
|
+ blueWeberContrastHigh = para.bluemeanintensity + (para.blueContrast * para.bluemeanintensity);
|
|
|
+ blueWeberContrastLow = para.bluemeanintensity - (para.blueContrast * para.bluemeanintensity);
|
|
|
+
|
|
|
+else
|
|
|
+ seed = para.seed;
|
|
|
+ whiteWeberContrastHigh = para.meanintensity + (para.contrast * para.meanintensity);
|
|
|
+ whiteWeberContrastLow = para.meanintensity - (para.contrast * para.meanintensity);
|
|
|
+end
|
|
|
+
|
|
|
+while ishandle(fh)
|
|
|
+
|
|
|
+ if para.color
|
|
|
+ % red
|
|
|
+ [checkerred, seed1] = ran1(seed1,para.Nx*para.Ny);
|
|
|
+ checkerred = single((checkerred > para.redmeanintensity) .* redWeberContrastHigh);
|
|
|
+ checkerred(checkerred == 0) = redWeberContrastLow;
|
|
|
+ checkerred = reshape(checkerred,para.Ny,para.Nx);
|
|
|
+ % green
|
|
|
+ [checkergreen, seed2] = ran1(seed2,para.Nx*para.Ny);
|
|
|
+ checkergreen = single((checkergreen > para.greenmeanintensity) .* greenWeberContrastHigh);
|
|
|
+ checkergreen(checkergreen == 0) = greenWeberContrastLow;
|
|
|
+ checkergreen = reshape(checkergreen,para.Ny,para.Nx);
|
|
|
+ % blue
|
|
|
+ [checkerblue, seed3] = ran1(seed3,para.Nx*para.Ny);
|
|
|
+ checkerblue = single((checkerblue > para.bluemeanintensity) .* blueWeberContrastHigh);
|
|
|
+ checkerblue(checkerblue == 0) = blueWeberContrastLow;
|
|
|
+ checkerblue = reshape(checkerblue,para.Ny,para.Nx);
|
|
|
+ % put all colors together
|
|
|
+ checker = cat(3,checkerred,checkergreen,checkerblue);
|
|
|
+ else
|
|
|
+ % black & white checker
|
|
|
+ [checker, seed] = ran1(seed,para.Nx*para.Ny);
|
|
|
+ checker = single((checker > para.meanintensity) .* whiteWeberContrastHigh);
|
|
|
+ checker(checker == 0) = whiteWeberContrastLow;
|
|
|
+ checker = reshape(checker,para.Ny,para.Nx);
|
|
|
+ checker = repmat(checker,1,1,3);
|
|
|
+ end
|
|
|
+
|
|
|
+ if framecounter == 0
|
|
|
+ rf = imagesc(xax,yax, checker);
|
|
|
+ axis(ah,[0, para.screensize(1),0, para.screensize(2)]);
|
|
|
+ set(ah,'Color',0.5*[1 1 1]); % this is to have gray background with margins
|
|
|
+ else
|
|
|
+ rf.CData = checker;
|
|
|
+ end
|
|
|
+
|
|
|
+ % this is to draw the frames relatively accurately.
|
|
|
+ drawnow;
|
|
|
+ java.lang.Thread.sleep(para.nblinks/para.refreshrate*1e3);
|
|
|
+ %pause(1/para.refreshrate);
|
|
|
+ framecounter = framecounter+1;
|
|
|
+end
|
|
|
+
|
|
|
+end
|
|
|
+
|
|
|
+%--------------------------------------------------------------------------------------------------%
|
|
|
+%---------- sub-functions ----------%
|
|
|
+%--------------------------------------------------------------------------------------------------%
|
|
|
+
|
|
|
+function paraout = read_stimulus_parameters(varargin)
|
|
|
+
|
|
|
+% first parse the user inputs
|
|
|
+p = inputParser(); % check the user options.
|
|
|
+
|
|
|
+validtruefalse = @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1]));
|
|
|
+p.addParameter('selecttextfile', false, validtruefalse);
|
|
|
+p.addParameter('stixelwidth', 6, @isnumeric);
|
|
|
+p.addParameter('stixelheight', 6, @isnumeric);
|
|
|
+p.addParameter('blackwhite', true, validtruefalse);
|
|
|
+p.addParameter('contrast',1, @isnumeric);
|
|
|
+p.addParameter('meanintensity', 0.5, @isnumeric);
|
|
|
+p.addParameter('seed', -1000, @isnumeric);
|
|
|
+p.addParameter('secondseed', -10000, @isnumeric);
|
|
|
+p.addParameter('thirdseed', -2000, @isnumeric);
|
|
|
+p.addParameter('nblinks', 2, @isnumeric);
|
|
|
+p.addParameter('lmargin',0, @isnumeric);
|
|
|
+p.addParameter('rmargin', 0, @isnumeric);
|
|
|
+p.addParameter('bmargin', 0, @isnumeric);
|
|
|
+p.addParameter('tmargin', 0, @isnumeric);
|
|
|
+p.addParameter('color', false, validtruefalse);
|
|
|
+p.addParameter('coneisolating', true, validtruefalse);
|
|
|
+p.addParameter('redmeanintensity', 0, @isnumeric);
|
|
|
+p.addParameter('greenmeanintensity', 0.5, @isnumeric);
|
|
|
+p.addParameter('bluemeanintensity', 0.5, @isnumeric);
|
|
|
+p.addParameter('redContrast', 0, @isnumeric);
|
|
|
+p.addParameter('greenContrast', 0.75, @isnumeric);
|
|
|
+p.addParameter('blueContrast', 0.75, @isnumeric);
|
|
|
+p.addParameter('screensize', [864 480], @isnumeric);
|
|
|
+p.addParameter('refreshrate', 60, @isnumeric);
|
|
|
+p.addParameter('fullscreen', false, validtruefalse);
|
|
|
+p.addParameter('help', false, validtruefalse);
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+% stimsize = [0+para.bmargin, 0+para.lmargin, para.screensize(1)-para.rmargin,...
|
|
|
+% para.screensize(2)-para.tmargin];
|
|
|
+xpixels = paraout.screensize(1) - (paraout.lmargin + paraout.rmargin);
|
|
|
+ypixels = paraout.screensize(2) - (paraout.tmargin + paraout.bmargin);
|
|
|
+paraout.Nx = ceil(xpixels / paraout.stixelwidth);
|
|
|
+paraout.Ny = ceil(ypixels / paraout.stixelheight);
|
|
|
+
|
|
|
+if paraout.stixelwidth > xpixels, paraout.stixelwidth = xpixels-1; end
|
|
|
+if paraout.stixelheight > ypixels, paraout.stixelheight = ypixels-1; end
|
|
|
+
|
|
|
+if paraout.fullscreen
|
|
|
+ monitorsize = get(0,'ScreenSize');
|
|
|
+ paraout.screensize = monitorsize(3:4) ;
|
|
|
+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
|