Using NewStim
Sections to be added:
Creating and running stimuli from the command line / functions / scripts
Remote communication and creating a stimulus slave machine
Synchronization with other devices
Ready-made GUI systems developed in the lab that use NewStim / remote communication
Testing stimulus timing on your system
Creating and running stimuli from the command line / functions / scripts
Let's jump right in and create a few stimuli. You can create a stimulus from the command line by calling its constructor class (such as periodicstim, stochasticgridstim, etc.; see NewStimList for a list of stimulus types known to NewStim). I recommend entering this text by hand rather than cutting and pasting so you learn the commands. Bold indicates built-in functions in NewStim or other software packages where indicated.
Creating stimuli (will not display them yet!)
sgs = stochasticgridstim('graphical') % this will create a new stimulus, letting you select the parameters graphically
% note: stochasticgridstim is a random-noise grid stimulus that lets you
% choose the grid size, colors, statistical distribution, etc)
You can also create a stimulus without using a graphical interface, using
sgs = stochasticgridstim('default') % will use default parameters
or
sgs = stochasticgridstim(parameters); % will use specified parameters;
%if you haven't specified any, this will cause an error
where parameters is a properly formatted parameter set for the constructor. How do you know what parameters a stimulus takes? There are 2 ways to find out. The best way is to call help stimclass or help stimclass/setparameters such as help stochasticgridstim. You can also use parameters = getparameters(mystim) to see the structure of the parameters for that particular stimulus, and that might help you figure out how to set parameters for a new stimulus.
parameters = getparameters(sgs) % will list the parameters for sgs
Food for thought: setting parameters is useful when creating a stimulus, but there are 2 situations where getting the parameters is useful. The first, and most obvious, is in performing data analysis. We'd like to see exactly what was run. If one saves the stimuli that were running (usually in the form of a stimscript, see below), then you have a perfect log of the parameters for each stimulus (and will be able to reconstruct it pixel by pixel, frame by frame). Second, you might have some code that will take a set of user-specified parameters and vary one or more of them systematically. This code could call getparameters, and create a new family of stimuli where one parameter is systematically varied while all other parameters are held constant.
Displaying stimuli
In order to display stimuli, they must be grouped into objects called stimscripts. The stimscript class allows you to specify the display order, either sequentially, randomly, or in an exact order that you specify. Let's create a stimulus, make a stimscript, add our stimulus to the script, load the script, and run it.
ps = periodicstim('default'); % we'll use a periodicstim this time
mynewscript = stimscript(0); % make a new stimscript; the argument of '0' is necessary because when I made
% this routine either Matlab was not capable of having a creator function with no
% arguments, or I couldn't figure out how to do it. At any rate, the argument
% needs to be there but the value doesn't matter and isn't used.
mynewscript = append(mynewscript,ps); % add the stimulus to the stimscript
mynewscript = setDisplayMethod(mynewscript,1,5); % will display the stimulus 5 times in random order; there's only
% 1 stim in this script, so it will be repeated 5 times
% if there were more, they would be presented in pseudorandom order.
do = getDisplayOrder(mynewscript); % return the display order; should be [ 1 1 1 1 1] indicating that stimulus 1
% will be presented 5 times in a row.
% if you only have 1 monitor, then I'd recommend copying and pasting the next 6 commands, as you won't be
% able to see what you're typing when the StimScreen is up
ShowStimScreen; % open the stimscreen window
mynewscript = loadStimScript(mynewscript);% preload all the stimulus frames into memory %
MTI = DisplayTiming(mynewscript); % creates an MTI structure; MTI stands for Measured Timing index I think;
% I made it in 2000 and can't exactly remember what it stands for
% The MTI basically does 2 things; 1) it pre-creates all of the arrays that
% will be used to hold timing information so they do not need to be created
% during the display, and 2) performs Gamma correction if this is to be used.
[MTI2,start] = DisplayStimScript(mynewscript,MTI,1,1); % actually performs the stimulus display
% The arguments to DisplayStimScript are 1) the script to be displayed,
% 2) the MTI (or empty, and the MTI will be computed before display),
% 3) the priority level at which the stims should run (see help Priority,
% a PsychToolbox function)
% 4) a 0/1 "abortable" value indicating whether or not the stimulus
% computer should look for a keypress between stims that would abort the
% script's run
mynewscript = unloadStimScript(mynewscript); % release the script from memory
CloseStimScreen; % close the stimulus screen
If something goes wrong during this code, and you only have 1 monitor, you won't be able to see what happened. In this case, a useful escape is to type in sca or screen('CloseAll'); (sca is a script shortcut for this longer command.) This command will close all open screens in the PsychToolbox and return you to plain old Matlab. This is a Psychophysics Toolbox function that is really useful to know if you have 1 monitor.
More about stimuli and scripts
Making a simple tuning curve stim with an interstimulus interval and a blank stimulus
Suppose you want to make a set of sinusoidal gratings (implemented in periodicstim) that vary in the direction of drifting motion. One way to do it would be the following.
ps = periodicstim('default'); % make a default periodicstim
p = getparameters(ps); % get the parameters for this default stimulus
p.dispprefs = {'BGpretime', 5, 'BGposttime', 0}; % this is the way to set the amount of background screen
% time before and after the stimulus is presented.
% The screen will be blank for 5 seconds before each
% stimulus, and transition immediately to the next stim
mydirs = [ 0:30:360-30 ] % make a vector of directions to use for stimulation
myscript = stimscript(0); % make an empty script
for i=1:length(mydirs),
p.angle = mydirs(i); % set the angle parameter to be the direction we want
mynewstim = periodicstim(p); % make a new stimulus
myscript = append(myscript,mynewstim); % and add it to the script
end;
myscript = addblank(myscript, [128 128 128]); % add a blank stim that is gray in color
myscript = setDisplayMethod(myscript,5,1); % repeat these stims 5 times each
% you might want to know how long these stims will take to run before you run them
timeitshouldtake = duration(myscript); % how long will the script take?
timeitshouldtakestim1 = duration(get(myscript,1)); % how long is stim 1?
% now for the display; if you have 1 monitor, you might want to cut and paste this part
ShowStimScreen;
myscript = loadStimScript(myscript);
MTI = DisplayTiming(myscript);
[MTI2,start] = DisplayStimScript(myscript,MTI,1,1);
myscript = unloadStimScript(myscript);
CloseStimScreen;
Remote communication and creating a stimulus slave machine
It is possible to send commands to a remote stimulus computer. NewStim has a RemoteComm directory that provides these services. At present, the way to do this is through file sharing; mount a shared network drive on the remote stimulus computer that can also be mounted by (or perhaps resides on) the master computer. Follow the installation instructions to set up the NewStimCalibrate.m file for both machines (so they both have the pathname of the drive as their remote path).
Then, on the remote computer, run the command initstims, The computer will switch to the remote directory and begin looking for commands to appear.
You can initiate commands from the remote computer using the sendremotecommand and sendremotecommandvar commands.
For example, you might use the following to run a script on a remote computer and save the timing output:
[b]=sendremotecommandvar(str,{'thescript','priority', 'abortable','saveit','mypath','myname','myremotepath', 'stimvalues'}, {thescript,priority,abortable,saveit,mypath,myname,myremotepath,sv});
%where
str = { 'save gotit abortable -mat;' % saving the 'gotit' file indicates to the master that the slave received the command
'thescript = loadstimscript(thescript);'
'mti=DisplayTiming(thescript);'
'[MTI2,start]=DisplayStimScript(thescript,mti,priority,abortable);'
'saveScript = strip(unloadStimScript(thescript));' % remove the memory buffers so we don't save those
'MTI2 = stripMTI(MTI2);'
'try, snd(''play'',''glass'');snd(''play'',''glass'');snd(''play'',''glass''); end;'
'if saveit, disp([''saving now, to '' fixpath(myremotepath) myname filesep ''stims.mat'']); end;'
'if saveit, try, mkdir(myremotepath,myname); end; save([fixpath(myremotepath) myname filesep ''stims.mat''],''saveScript'',''start'',''MTI2'',''-mat''); end;'
};
Ready-made GUI systems that use NewStim / remote communication
Probably 3/4 of all users will not use NewStim directly from the command line or their own functions, but will rather use a ready-made graphical user interface (GUI) that employs the NewStim system.
To my knowledge, there are 2 of these systems:
The RunExperiment environment, originally developed by Steve in the Nelson lab.
FitzStim4, originally developed by Tom Tucker, and extended by Steve to include support for NewStim. This is used in the Fitzpatrick lab at Duke.
Testing stimulus timing on your system
[Under construction!]
StimWindowGlobals;
figure;
plot(diff(MTI2{1}.frameTimes));
hold on;
plot(1:length(MTI2{1}.frameTimes)-1, ...
ones(1,length(MTI2{1}.frameTimes)-1)*mean(diff(MTI2{1}.frameTimes))+1/StimWindowRefresh,'g--');
plot(1:length(MTI2{1}.frameTimes)-1, ...
ones(1,length(MTI2{1}.frameTimes)-1)*mean(diff(MTI2{1}.frameTimes))-1/StimWindowRefresh,'g--');
end;