function GratingDemo
% GratingDemo
%
% Displays a stationary grating. See also DriftDemo, DriftDemo2, DriftDemo3 and DriftWaitDemo.
% ---------- Program History ----------
% 07/01/1999 dgp Added arbitrary orientation.
% 12/10/2001 awi Added font conditional.
% 02/21/2002 dgp Mentioned DriftDemo.
% 04/03/2002 awi Merged OS9 and Win versions, which had fallen out of sync.
% 04/13/2002 dgp Used Arial, eliminating need for conditional.
% 07/15/2003 dgp Added comments explaining f and lambda.
% 08/16/2006 rhh Added user-friendly parameters, such as tiltInDegrees,
% pixelsPerPeriod, periodsCoveredByOneStandardDeviation and widthOfGrid.
% 08/18/2006 rhh Expanded comments and created comment sections.
% 10/04/2006 dhb Minimize warnings.
% 10/11/2006 dhb Use maximum available screen.
% 10/14/2006 dhb Save and restore altered prefs, more extensive comments for them
% 07/12/2006 prf Changed method of rotating the grating
% ---------- Parameter Setup ----------
% Initializes the program's parameters.
% Prevents MATLAB from reprinting the source code when the program runs.
echo off
% *** To rotate the grating, set tiltInDegrees to a new value.
tiltInDegrees = 7; % The tilt of the grating in degrees.
tiltInRadians = tiltInDegrees * pi / 180; % The tilt of the grating in radians.
% *** To lengthen the period of the grating, increase pixelsPerPeriod.
pixelsPerPeriod = 33; % How many pixels will each period/cycle occupy?
spatialFrequency = 1 / pixelsPerPeriod; % How many periods/cycles are there in a pixel?
radiansPerPixel = spatialFrequency * (2 * pi); % = (periods per pixel) * (2 pi radians per period)
% *** To enlarge the gaussian mask, increase periodsCoveredByOneStandardDeviation.
% The parameter "periodsCoveredByOneStandardDeviation" is approximately
% equal to
% the number of periods/cycles covered by one standard deviation of the radius of
% the gaussian mask.
periodsCoveredByOneStandardDeviation = 1.5;
% The parameter "gaussianSpaceConstant" is approximately equal to the
% number of pixels covered by one standard deviation of the radius of
% the gaussian mask.
gaussianSpaceConstant = periodsCoveredByOneStandardDeviation * pixelsPerPeriod;
% *** If the grating is clipped on the sides, increase widthOfGrid.
widthOfGrid = 400;
halfWidthOfGrid = widthOfGrid / 2;
widthArray = (-halfWidthOfGrid) : halfWidthOfGrid; % widthArray is used in creating the meshgrid.
% For an explanation of the try-catch block, see the section "Error Handling"
% at the end of this document.
try
% ---------- Window Setup ----------
% Opens a window.
% Screen is able to do a lot of configuration and performance checks on
% open, and will print out a fair amount of detailed information when
% it does. These commands supress that checking behavior and just let
% the demo go straight into action. See ScreenTest for an example of
% how to do detailed checking.
oldVisualDebugLevel = Screen('Preference', 'VisualDebugLevel', 3);
oldSupressAllWarnings = Screen('Preference', 'SuppressAllWarnings', 1);
% Find out how many screens and use largest screen number.
whichScreen = max(Screen('Screens'));
% Opens a graphics window on the main monitor (screen 0). If you have
% multiple monitors connected to your computer, then you can specify
% a different monitor by supplying a different number in the second
% argument to OpenWindow, e.g. Screen('OpenWindow', 2).
window = Screen('OpenWindow', whichScreen);
% Hides the mouse cursor
HideCursor;
% ---------- Color Setup ----------
% Gets color values.
% Retrieves color codes for black and white and gray.
black = BlackIndex(window); % Retrieves the CLUT color code for black.
white = WhiteIndex(window); % Retrieves the CLUT color code for white.
gray = (black + white) / 2; % Computes the CLUT color code for gray.
if round(gray)==white
gray=black;
end
% Taking the absolute value of the difference between white and gray will
% help keep the grating consistent regardless of whether the CLUT color
% code for white is less or greater than the CLUT color code for black.
absoluteDifferenceBetweenWhiteAndGray = abs(white - gray);
% ---------- Image Setup ----------
% Stores the image in a two dimensional matrix.
% Creates a two-dimensional square grid. For each element i = i(x0, y0) of
% the grid, x = x(x0, y0) corresponds to the x-coordinate of element "i"
% and y = y(x0, y0) corresponds to the y-coordinate of element "i"
[x y] = meshgrid(widthArray, widthArray);
% Replaced original method of changing the orientation of the grating
% (gradient = y - tan(tiltInRadians) .* x) with sine and cosine (adapted from DriftDemo).
% Use of tangent was breakable because it is undefined for theta near pi/2 and the period
% of the grating changed with change in theta.
a=cos(tiltInRadians)*radiansPerPixel;
b=sin(tiltInRadians)*radiansPerPixel;
% Converts meshgrid into a sinusoidal grating, where elements
% along a line with angle theta have the same value and where the
% period of the sinusoid is equal to "pixelsPerPeriod" pixels.
% Note that each entry of gratingMatrix varies between minus one and
% one; -1 <= gratingMatrix(x0, y0) <= 1
gratingMatrix = sin(a*x+b*y);
% Creates a circular Gaussian mask centered at the origin, where the number
% of pixels covered by one standard deviation of the radius is
% approximately equal to "gaussianSpaceConstant."
% For more information on circular and elliptical Gaussian distributions, please see
% http://mathworld.wolfram.com/GaussianFunction.html
% Note that since each entry of circularGaussianMaskMatrix is "e"
% raised to a negative exponent, each entry of
% circularGaussianMaskMatrix is one over "e" raised to a positive
% exponent, which is always between zero and one;
% 0 < circularGaussianMaskMatrix(x0, y0) <= 1
circularGaussianMaskMatrix = exp(-((x .^ 2) + (y .^ 2)) / (gaussianSpaceConstant ^ 2));
% Since each entry of gratingMatrix varies between minus one and one and each entry of
% circularGaussianMaskMatrix vary between zero and one, each entry of
% imageMatrix varies between minus one and one.
% -1 <= imageMatrix(x0, y0) <= 1
imageMatrix = gratingMatrix .* circularGaussianMaskMatrix;
% Since each entry of imageMatrix is a fraction between minus one and
% one, multiplying imageMatrix by absoluteDifferenceBetweenWhiteAndGray
% and adding the gray CLUT color code baseline
% converts each entry of imageMatrix into a shade of gray:
% if an entry of "m" is minus one, then the corresponding pixel is black;
% if an entry of "m" is zero, then the corresponding pixel is gray;
% if an entry of "m" is one, then the corresponding pixel is white.
grayscaleImageMatrix = gray + absoluteDifferenceBetweenWhiteAndGray * imageMatrix;
% ---------- Image Display ----------
% Displays the image in the window.
% Colors the entire window gray.
Screen('FillRect', window, gray);
% Writes the image to the window.
Screen('PutImage', window, grayscaleImageMatrix);
% Writes text to the window.
currentTextRow = 0;
Screen('DrawText', window, sprintf('black = %d, white = %d', black, white), 0, currentTextRow, black);
currentTextRow = currentTextRow + 20;
Screen('DrawText', window, 'Press any key to exit.', 0, currentTextRow, black);
% Updates the screen to reflect our changes to the window.
Screen('Flip', window);
% Waits for the user to press a key.
KbWait;
% ---------- Window Cleanup ----------
% Closes all windows.
sca;
% Restores the mouse cursor.
ShowCursor;
% Restore preferences
Screen('Preference', 'VisualDebugLevel', oldVisualDebugLevel);
Screen('Preference', 'SuppressAllWarnings', oldSupressAllWarnings);
catch
% ---------- Error Handling ----------
% If there is an error in our code, we will end up here.
% The try-catch block ensures that Screen will restore the display and return us
% to the MATLAB prompt even if there is an error in our code. Without this try-catch
% block, Screen could still have control of the display when MATLAB throws an error, in
% which case the user will not see the MATLAB prompt.
sca;
% Restores the mouse cursor.
ShowCursor;
% Restore preferences
Screen('Preference', 'VisualDebugLevel', oldVisualDebugLevel);
Screen('Preference', 'SuppressAllWarnings', oldSupressAllWarnings);
% We throw the error again so the user sees the error description.
psychrethrow(psychlasterror);
end