diff --git a/MemExperiments/ColorWorkingMemoryExperiment.asv b/MemExperiments/ColorWorkingMemoryExperiment.asv new file mode 100644 index 0000000..e8bc381 --- /dev/null +++ b/MemExperiments/ColorWorkingMemoryExperiment.asv @@ -0,0 +1,235 @@ +% COLORWORKINGMEMORYEXPERIMENT Runs a color working memory task +% a la Zhang & Luck (2008). The task requires memory for the color of +% briefly presented squares. Participants then report the color of a single +% probed square using a continuous report task. +% +% ColorWorkingMemoryExperiment(); +% +% Preferences can be found down at the bottom, beginning on line 197. +% + +function ColorWorkingMemoryExperiment() + + try + prepareEnvironment; + window = openWindow(); + prefs = getPreferences() + + % Put up instructions and wait for keypress. + instruct(window); + returnToFixation(window, window.centerX, window.centerY, prefs.fixationSize) + + WaitSecs(1); + + % Get rects for each item. + rects = cell(1, max(prefs.setSizes)); + for i = 1:max(prefs.setSizes) + rects{i} = circularArrayRects([0, 0, prefs.squareSize, prefs.squareSize], ... + i, prefs.radius, window.centerX, window.centerY)'; + end + + colorWheelLocations = colorwheelLocations(window,prefs); + + for trialIndex = 1:length(prefs.fullFactorialDesign) + + % Determine how many items there are on this trial and the duration. + nItems = prefs.setSizes(prefs.fullFactorialDesign(prefs.order(trialIndex), 1)); + retentionInterval = prefs.retentionIntervals(prefs.fullFactorialDesign(prefs.order(trialIndex), 2)); + + % Pick an item to test. + itemToTest(trialIndex) = PsychRandSample(1:nItems); + + % Pick the colors for this trial. + colorsInDegrees{trialIndex} = ceil(rand(1, nItems)*360); + + % Draw fixation. + drawFixation(window, window.centerX, window.centerY, prefs.fixationSize); + + % Draw the stimulus. + colorsToDisplay = prefs.colorwheel(colorsInDegrees{trialIndex}, :)'; + Screen('FillRect', window.onScreen, colorsToDisplay, rects{nItems}); + + % Post the stimulus and wait. + Screen('Flip', window.onScreen); + WaitSecs(prefs.stimulusDuration); + + % Remove stimulus, return to blank, wait for retention interval to pass. + returnToFixation(window, window.centerX, window.centerY, prefs.fixationSize); + WaitSecs(retentionInterval); + + % Choose a circle to test, then display the response screen. + data.presentedColor(trialIndex) = deg2rad(colorsInDegrees{trialIndex}(itemToTest(trialIndex))); + colorsOfTest = repmat([120 120 120], nItems, 1); + colorsOfTest(itemToTest(trialIndex), :) = [145 145 145]; + drawFixation(window, window.centerX, window.centerY, prefs.fixationSize); + Screen('FillRect', window.onScreen, colorsOfTest', rects{nItems}); + + drawColorWheel(window, prefs); + + % Wait for click. + SetMouse(window.centerX, window.centerY); + ShowCursor('Arrow'); + + % If mouse button is already down, wait for release. + [x, y, buttons]GetMouse(window.onScreen); + while any(buttons) + [x, y, buttons] = GetMouse(window.onScreen); + end + + everMovedFromCenter = false; + while ~any(buttons) + + drawColorWheel(window, prefs); + + [x,y,buttons] = GetMouse(window.onScreen); + [minDistance, minDistanceIndex] = min(sqrt((colorWheelLocations(1, :) - x).^2 + (colorWheelLocations(2, :) - y).^2)); + + if(minDistance < 250) + everMovedFromCenter = true; + end + + if(everMovedFromCenter) + colorsOfTest(itemToTest(trialIndex), :) = prefs.colorwheel(minDistanceIndex,:); + else + colorsOfTest(itemToTest(trialIndex), :) = [145 145 145]; + end + + drawFixation(window, window.centerX, window.centerY, prefs.fixationSize); + Screen('FillRect', window.onScreen, colorsOfTest', rects{nItems}); + drawColorWheel(window, prefs); + Screen('Flip', window.onScreen); + end + data.reportedColor(trialIndex) = deg2rad(minDistanceIndex); + while any(buttons) % wait for release + [x,y,buttons] = GetMouse(window.onScreen); + end + + HideCursor + + % Return to fixation. + returnToFixation(window, window.centerX, window.centerY, prefs.fixationSize); + WaitSecs(0.5); + end + + % Preliminary analysis of results. + data.error = (180/pi) .* (angle(exp(1i*data.reportedColor)./exp(1i*data.presentedColor))); + data.setSize = prefs.setSizes(prefs.fullFactorialDesign(prefs.order, 1)); + data.retentionInterval = prefs.retentionIntervals(prefs.fullFactorialDesign(prefs.order,2)); + + save data.mat data prefs + postpareEnvironment; + + catch ME + rethrow(ME) + postpareEnvironment; + psychrethrow(psychlasterror); + + end % end try/catch +end % end whole colorworkingmemoryscript + +function prepareEnvironment + + clear all; + HideCursor; + + commandwindow; % Select the command window to avoid typing in open scripts + + % Seed the random number generator. + % RandStream.setDefaultStream was renamed to RandStream.setGlobalStream in + % R2011a + if verLessThan('matlab','7.12') + RandStream.setDefaultStream(RandStream('mt19937ar', 'seed', sum(100*clock))); + else + RandStream.setGlobalStream(RandStream('mt19937ar', 'seed', sum(100*clock))); + end + + ListenChar(2); % Don't print to MATLAB command window +end + +function postpareEnvironment + ShowCursor; + ListenChar(0); + Screen('CloseAll'); +end + +function instruct(window) + Screen('TextSize', window.onScreen, window.fontsize); + Screen('DrawText', window.onScreen, 'Remember the colors. Click to begin.', 100, 100, 255); + Screen('Flip', window.onScreen); + GetClicks(window.onScreen); +end + +function drawFixation(window, fixationX, fixationY, fixationSize) + Screen('DrawDots', window.onScreen, [fixationX, fixationY], fixationSize, 255); +end + +function offsets = circularArrayOffsets(n, centerX, centerY, radius, rotation) + degreeStep = 360/n; + offsets = [sind(0:degreeStep:(360-degreeStep) + rotation)'.* radius, ... + cosd(0:degreeStep:(360-degreeStep) + rotation)'.* radius]; +end + +function rects = circularArrayRects(rect, nItems, radius, centerX, centerY) + coor = circularArrayOffsets(nItems, centerX, centerY, radius, 0) + repmat([centerX centerY], nItems, 1); + rects = [coor(:, 1)-rect(3)/2 , coor(:, 2)-rect(3)/2, coor(:, 1)+rect(3)/2, coor(:, 2)+rect(3)/2]; +end + +function returnToFixation(window, fixationX, fixationY, fixationSize) + Screen('FillRect', window.onScreen, window.bcolor); + Screen('DrawDots', window.onScreen, [fixationX, fixationY], fixationSize, 255); + Screen('Flip', window.onScreen); +end + +function window = openWindow() + window.screenNumber = max(Screen('Screens')); + window.onScreen = Screen('OpenWindow', window.screenNumber, [128 128 128]); + Screen('BlendFunction', window.onScreen, 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA'); + [window.screenX, window.screenY] = Screen('WindowSize', window.onScreen); % check resolution + window.screenRect = [0, 0, window.screenX, window.screenY]; % screen rect + window.centerX = window.screenX * 0.5; % center of screen in X direction + window.centerY = window.screenY * 0.5; % center of screen in Y direction + window.centerXL = floor(mean([0, window.centerX])); % center of left half of screen in X direction + window.centerXR = floor(mean([window.centerX, window.screenX])); % center of right half of screen in X direction + + % Basic drawing and screen variables. + window.black = BlackIndex(window.onScreen); + window.white = WhiteIndex(window.onScreen); + window.gray = mean([window.black window.white]); + window.fontsize = 24; + window.bcolor = window.gray; +end + +function drawColorWheel(window, prefs) + colorWheelLocations = [cosd(1:360).*prefs.colorWheelRadius + window.centerX; ... + sind(1:360).*prefs.colorWheelRadius + window.centerY]; + colorWheelSizes = 20; + Screen('DrawDots', window.onScreen, colorWheelLocations, colorWheelSizes, prefs.colorwheel', [], 1); +end + +function L = colorwheelLocations(window,prefs) + L = [cosd(1:360).*prefs.colorWheelRadius + window.centerX; ... + sind(1:360).*prefs.colorWheelRadius + window.centerY]; +end + +function prefs = getPreferences + prefs.nTrialsPerCondition = 2; + prefs.setSizes = [2,4]; + prefs.retentionIntervals = [0.250, 0.5, 1]; + prefs.stimulusDuration = 0.250; + prefs.squareSize = 75; % size of each stimulus object, in pixels + prefs.radius = 180; + prefs.fixationSize = 3; + + % Colorwheel details. + prefs.colorWheelRadius = 350; + prefs.colorwheel = load('colorwheel360.mat', 'fullcolormatrix'); + prefs.colorwheel = prefs.colorwheel.fullcolormatrix; + + % Randomize trial order of full factorial design order. + prefs.fullFactorialDesign = fullfact([length(prefs.setSizes), ... + length(prefs.retentionIntervals), ... + prefs.nTrialsPerCondition]); + + prefs.order = Shuffle(1:length(prefs.fullFactorialDesign)); + prefs.nTrials = length(prefs.fullFactorialDesign); +end diff --git a/MemExperiments/ColorWorkingMemoryExperiment.m b/MemExperiments/ColorWorkingMemoryExperiment.m index 25c4639..908e83d 100644 --- a/MemExperiments/ColorWorkingMemoryExperiment.m +++ b/MemExperiments/ColorWorkingMemoryExperiment.m @@ -37,7 +37,7 @@ function ColorWorkingMemoryExperiment() retentionInterval = prefs.retentionIntervals(prefs.fullFactorialDesign(prefs.order(trialIndex), 2)); % Pick an item to test. - itemToTest(trialIndex) = RandSample(1:nItems); + itemToTest(trialIndex) = PsychRandSample(1:nItems); % Pick the colors for this trial. colorsInDegrees{trialIndex} = ceil(rand(1, nItems)*360); @@ -71,7 +71,7 @@ function ColorWorkingMemoryExperiment() ShowCursor('Arrow'); % If mouse button is already down, wait for release. - GetMouse(window.onScreen); + [x, y, buttons] = GetMouse(window.onScreen); while any(buttons) [x, y, buttons] = GetMouse(window.onScreen); end @@ -134,7 +134,13 @@ function ColorWorkingMemoryExperiment() commandwindow; % Select the command window to avoid typing in open scripts % Seed the random number generator. - RandStream.setDefaultStream(RandStream('mt19937ar', 'seed', sum(100*clock))); + % RandStream.setDefaultStream was renamed to RandStream.setGlobalStream in + % R2011a + if verLessThan('matlab','7.12') + RandStream.setDefaultStream(RandStream('mt19937ar', 'seed', sum(100*clock))); + else + RandStream.setGlobalStream(RandStream('mt19937ar', 'seed', sum(100*clock))); + end ListenChar(2); % Don't print to MATLAB command window end diff --git a/MemPlots/PlotPosteriorComparison.m b/MemPlots/PlotPosteriorComparison.m index 53d76f0..9f1da03 100644 --- a/MemPlots/PlotPosteriorComparison.m +++ b/MemPlots/PlotPosteriorComparison.m @@ -1,6 +1,6 @@ %PLOTPOSTERIORCOMPARISON Show multiple posteriors at once (e.g., for two conditions) % -% figHand = PlotPosteriorComparison(posteriors, paramNames) +% figHand = PlotPosteriorComparison(posteriors, paramNames, conditionOrder) % % Example usage: % posteriorSamples1 = MCMC(MemDataset(1), model); @@ -12,7 +12,12 @@ % Posteriors can be either fullPosteriors or posteriorSamples or a mixture % of the two. % -function figHand = PlotPosteriorComparison(posteriors, paramNames) +% The optional third argument "conditionOrder" can be used to plot +% condition names instead of numbers. The output from +% [datasets, conditionOrder] = SplitDataByCondition(data) +% can be recycled. +% +function figHand = PlotPosteriorComparison(posteriors, paramNames, conditionOrder) % Show 2x2 correlation for each variable with each other to look for % structure; Visualize both as a scatter and as a 2D histogram figHand = figure; @@ -28,7 +33,11 @@ end N = length(paramNames); subplot(N,N,sub2ind([N N],N,1)); - l = legend(cl, num2str((1:length(posteriors))'), 'Location', 'NorthEast'); + if exist('conditionOrder','var') + l = legend(cl, conditionOrder, 'Location', 'NorthEast'); + else + l = legend(cl, num2str((1:length(posteriors))'), 'Location', 'NorthEast'); + end pos = get(l, 'Position'); set(l, 'Position', [pos(1)+0.05, pos(2)+0.04, pos(3), pos(4)]); end @@ -67,8 +76,13 @@ [n,x] = hist(posteriorSamples.vals(:,p)); n = n./max(n(:)); h1=bar(x,n, 'FaceColor',cols(w,:),'EdgeColor',cols(w,:)); - hPatch = findobj(h1,'Type','patch'); - set(hPatch,'FaceAlpha',0.4); + %different transparency handles starting R2014b + if verLessThan('matlab','8.5') + hPatch = findobj(h1,'Type','patch'); + set(hPatch,'FaceAlpha',0.4); + else + h1.FaceAlpha = 0.4; + end axis tight; xlim([min(xlim)-(max(xlim)-min(xlim))/3 max(xlim)+(max(xlim)-min(xlim))/3]); set(gca, 'YTick', []);