<?xml version="1.0" encoding="utf-8"?><!DOCTYPE article  PUBLIC '-//OASIS//DTD DocBook XML V4.4//EN'  'http://www.docbook.org/xml/4.4/docbookx.dtd'><article><articleinfo><title>ScannerSyncMatlab</title><revhistory><revision><revnumber>22</revnumber><date>2015-08-28 14:58:08</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>21</revnumber><date>2015-08-28 14:55:25</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>20</revnumber><date>2015-08-28 14:54:14</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>19</revnumber><date>2015-08-28 14:51:37</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>18</revnumber><date>2015-08-28 14:49:13</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>17</revnumber><date>2015-08-28 14:44:33</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>16</revnumber><date>2015-08-28 14:43:57</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>15</revnumber><date>2015-08-28 14:43:43</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>14</revnumber><date>2015-08-28 14:41:44</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>13</revnumber><date>2015-08-28 14:39:28</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>12</revnumber><date>2015-08-28 14:38:35</date><authorinitials>RussellThompson</authorinitials></revision><revision><revnumber>11</revnumber><date>2013-11-26 22:54:14</date><authorinitials>kalm</authorinitials></revision><revision><revnumber>10</revnumber><date>2013-11-26 22:53:23</date><authorinitials>kalm</authorinitials></revision><revision><revnumber>9</revnumber><date>2013-03-07 21:23:43</date><authorinitials>localhost</authorinitials><revremark>converted to 1.6 markup</revremark></revision><revision><revnumber>8</revnumber><date>2010-09-28 10:38:46</date><authorinitials>AnnikaLinke</authorinitials></revision><revision><revnumber>7</revnumber><date>2010-09-28 10:37:59</date><authorinitials>AnnikaLinke</authorinitials></revision><revision><revnumber>6</revnumber><date>2010-09-28 10:18:26</date><authorinitials>AnnikaLinke</authorinitials></revision><revision><revnumber>5</revnumber><date>2010-09-28 10:15:03</date><authorinitials>AnnikaLinke</authorinitials></revision><revision><revnumber>4</revnumber><date>2009-02-25 09:59:43</date><authorinitials>RhodriCusack</authorinitials></revision><revision><revnumber>3</revnumber><date>2009-02-25 09:59:01</date><authorinitials>RhodriCusack</authorinitials></revision><revision><revnumber>2</revnumber><date>2009-02-25 09:58:44</date><authorinitials>RhodriCusack</authorinitials></revision><revision><revnumber>1</revnumber><date>2009-02-25 09:58:32</date><authorinitials>RhodriCusack</authorinitials></revision></revhistory></articleinfo><section><title>*****</title></section><section><title>NB - as of early 2015, the method of using scanner sync in matlab has changed. The new method uses Tibor's ScannerSynchClass rather than Rhodri's MRISync / ScannerSync software</title></section><section><title>*****</title></section><section><title>Using ScannerSync from Matlab - NEW METHOD</title><para>Open Matlab and check that the <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/ScannerSynchClass#">ScannerSynchClass</ulink> is on the path, e.g. using: </para><screen><![CDATA[which ScannerSynchClass]]></screen><para>This should return the path to the <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/ScannerSynchClass#">ScannerSynchClass</ulink>.m file. On the stim machines, this should be C:\Program Files\MATLAB\R2014a\toolbox\CBSU. </para><para>If you get an error message like &quot;<ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/ScannerSynchClass#">ScannerSynchClass</ulink> not found&quot;, try: </para><screen><![CDATA[addpath('C:\Program Files\MATLAB\R2014a\toolbox\CBSU')]]></screen><para>Once the <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/ScannerSynchClass#">ScannerSynchClass</ulink> is available, create an instance of the class: </para><screen><![CDATA[SSO=ScannerSynchClass]]></screen><para>Once the instance has been created, you can use the class properties and methods to collect pulses and button box responses: </para><screen><![CDATA[== Properties (internal variables) ==
IsValid         = device set and operational
TR              = set a non-zero value (in seconds) for emulation mode (will not detect "real"          pulses)
Keys    = set a cell of key names for emulation mode. For key names look for KbName.m.
        N.B.: Requires PTB.
        N.B.: Suppress passing keypresses to MATLAB during the whole experiment
]]><![CDATA[
Clock   = interal clock (seconds past since the first scanner pulse or clock reset)
Synch   = current state of the scanner synch pulse
TimeOfLastPulse         = time (according to the internal clock) of the last pulse 
MeasuredTR      = estimated TR
SynchCount      = number of scanner synch pulses
MissedSynch     = number of missed scanner synch pulses
]]><![CDATA[
EmulSynch       = is scanner synch pulse emulated 
EmulButtons     = is button box emulated
%
Buttons                 = current state of the any button
LastButtonPress         = index/indices of the last button(s) pressed
TimeOfLastButtonPress   = time (according to the internal clock) of the last button press (any) 
BBoxTimeout     = set a non-Inf value (in seconds) to wait for button press only                               = set a negative value (in seconds) to wait even in case of response
]]><![CDATA[
== Methods (internal functions) ==
ScannerSynchClass       = constructor
delete  = destructor
ResetClock      = reset internal clock
]]><![CDATA[
ResetSynchCount         = reset scanner synch pulse counter
SetSynchReadoutTime(t)  = blocks scanner synch pulse readout after a pulse for 't' seconds
WaitForSynch    = wait until a scanner synch pulse arrives
CheckSynch(t)   = wait for a scanner synch pulse for 't' seconds or unitl a scanner synch pulse arrives (whichever first) and returns whether a scanner synch pulse was detected
]]><![CDATA[
        SetButtonReadoutTime(t)         = blocks individual button readout after a button press for 't' seconds (detection of other buttons is still possible) 
SetButtonBoxReadoutTime(t)      = blocks the whole button box readout after a button press for 't' seconds (detection of other buttons is also not possible) 
WaitForButtonPress                      = wait until a button is pressed
WaitForButtonRelease            = wait until a button is released
]]><![CDATA[
]]><![CDATA[
]]><![CDATA[
%
% USAGE
%
% Initialise:
%       SSO = ScannerSynchClass;
%       % SSO = ScannerSynchClass(1);   % emulate scanner synch pulse
%       % SSO = ScannerSynchClass(0,1); % emulate button box
%       % SSO = ScannerSynchClass(1,1); % emulate scanner synch pulse and button box
%
% Close:
%       SSO.delete;
%
% Example for scanner synch pulse #1: - Simple case
%       SSO.SetSynchReadoutTime(0.5);
%       SSO.TR = 2;                % allows detecting missing pulses
%       while SSO.SynchCount < 10  % polls 10 pulses
%       SSO.WaitForSynch;
%       fprintf('Pulse %d: %2.3f. Measured TR = %2.3fs\n',...
%           SSO.SynchCount,...
%           SSO.TimeOfLastPulse,...
%           SSO.MeasuredTR);
%       end
%
% Example for scanner synch pulse #2 - Chance for missing pulse
%       SSO.SetSynchReadoutTime(0.5);
%       SSO.TR = 2;                    % allows detecting missing pulses
%       while SSO.SynchCount < 10      % until 10 pulses
%       WaitSecs(Randi(100)/1000); % in every 0-100 ms ...
%       if SSO.CheckSynch(0.01)    % ... waits for 10 ms for a pulse
%               fprintf('Pulse %d: %2.3f. Measured TR = %2.3fs. %d synch pulses has/have been missed\n',...
%               SSO.SynchCount,...
%               SSO.TimeOfLastPulse,...
%               SSO.MeasuredTR,...
%               SSO.MissedSynch);
%       end
%       end
%
% Example for buttons:
%       SSO.SetButtonReadoutTime(0.5);      % block individual buttons
%       % SSO.SetButtonBoxReadoutTime(0.5); % block the whole buttonbox
%   % SSO.Keys = {'f1','f2','f3','f4'}; % emulation Buttons #1-#4 with F1-F4
%       n = 0;
%   % SSO.BBoxTimeout = 1.5;            % Wait for button press for 1.5s
%   % SSO.BBoxTimeout = -1.5;           % Wait for button press for 1.5s even in case of response
%       SSO.ResetClock;
%       while n ~= 10                       % polls 10 button presses
%       SSO.WaitForButtonPress;         % Wait for any button to be pressed
%       SSO.WaitForButtonRelease;       % Wait for any button to be     released
%       % SSO.WaitForButtonPress([],2); % Wait for Button #2
%       % SSO.WaitForButtonPress(2);    % Wait for any button for 2s (overrides SSO.BBoxTimeout only for this event)
%       % SSO.WaitForButtonPress(-2);   % Wait for any button for 2s even in case of response (overrides SSO.BBoxTimeout only for this event)
%       % SSO.WaitForButtonPress(2,2);  % Wait for Button #2 for 2s (overrides SSO.BBoxTimeout only for this event)
%       % SSO.WaitForButtonPress(-2,2); % Wait for Button #2 for 2s even in case of response (overrides SSO.BBoxTimeout only for this event)
%       n = n + 1;
%       fprintf('At %2.3fs, ',SSO.Clock);
%       fprintf('Button %d ',SSO.LastButtonPress);
%       fprintf('pressed: %2.3fs\n',SSO.TimeOfLastButtonPress);
%       end]]></screen></section><section><title>Using ScannerSync from Matlab - OLD METHOD</title><para>Make sure you have the <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/ScannerSync#">ScannerSync</ulink> control installed. </para><para>Somewhere near the top of your code, set up <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/ScannerSync#">ScannerSync</ulink> &amp; initialise communication with the input-output board (will not work if you're using a machine without the board, e.g., not the mimic or stim delivery machines). </para><screen><![CDATA[%% SCANNERSYNC
TR=1000; % TR in ms
numdummies=8;
]]><![CDATA[
% Create & initialise scanner sync object
objSS=actxserver('MRISync.ScannerSync');  %Create a scanner object
invoke(objSS,'Initialize','') %Initialise the Keithley board and object
invoke(objSS,'SetMSPerSample',2); %Set StartExperiment routines’ sampling]]></screen><para>Now, wait for first pulse from scanner. Also, tell <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/ScannerSync#">ScannerSync</ulink> the approximate TR. </para><screen><![CDATA[% ScannerSync - waits for the first pulse, resets timer to 0, sets TR
invoke(objSS,'StartExperiment', double(TR));]]></screen><para>Wait for dummies (one less as <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/StartExperiment#">StartExperiment</ulink> command above will already have heard a pulse) </para><screen><![CDATA[for countdown=(numdummies-1):-1:1
    count_text=sprintf('%d', countdown);
  % uncomment the next two if you're using the PsychToolbox
%    DrawFormattedText(window, count_text, 'center', 'center', white);
%    Screen(window, 'Flip');
    invoke(objSS,'SynchroniseExperiment',1,0); %  1= force wait for actual pulse; 0=return this many ms after pulse
end;]]></screen><para>In your trial loop, you'll need to spend some of the time listening for pulses </para><screen><![CDATA[    invoke(objSS,'CheckPulseSynchronyForTime', double(500)); % spend 500 ms listening for any pulses]]></screen><para>You should dump out the timing of critical events and the measured TR </para><screen><![CDATA[    picstarttime=invoke(objSS,'SSGetTimer');
    measuredTR=invoke(objSS,'GetMeasuredTR');
]]><![CDATA[
% ...add your own code to write these to your output file]]></screen><para>Also, for some designs you may want to occasionally synchronise your trials to the scanner </para><screen><![CDATA[    invoke(objSS,'SynchroniseExperiment',1,0); %  1= force wait for actual pulse; 0=return this many ms after pulse]]></screen><section><title>Using pretend mode</title><para>If you'd like to test code on a machine without the card, you may use a feature of <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/ScannerSync#">ScannerSync</ulink> called &quot;pretend mode&quot;. To do this: </para><para>(1) When in pretend mode, don't do &quot;Initialise&quot;, and instead issue a &quot;<ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/SetPretendMode#">SetPretendMode</ulink>&quot; command. So change the first block to something like </para><screen><![CDATA[pretendmode=1;
% Create & initialise scanner sync object
objSS=actxserver('MRISync.ScannerSync');  %Create a scanner object
if (~pretendmode)
  invoke(objSS,'Initialize','') %Initialise the Keithley board and object
else
  invoke(objSS,'SetPretendMode',1)
end;
invoke(objSS,'SetMSPerSample',2); %Set StartExperiment routines’ sampling]]></screen><para>(2) You'll then see a warning message when you get to the &quot;<ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/StartExperiment#">StartExperiment</ulink>&quot; command, to which you should click &quot;OK&quot;. If you're using the <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/PsychToolbox#">PsychToolbox</ulink> and have already set up the screen, make sure that you only use the <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/HideCursor#">HideCursor</ulink> command after the <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/StartExperiment#">StartExperiment</ulink> command, otherwise you won't be able to click OK. </para><para>If you would like to use the button box in the practice room of the Scanner building, you will need this code instead to make the button box work: </para><screen><![CDATA[pretendmode=1;
% Create & initialise scanner sync object
objSS=actxserver('MRISync.ScannerSync');  %Create a scanner object
if (~pretendmode)
  invoke(objSS,'Initialize','') %Initialise the Keithley board and object
else
  invoke(objSS,'SetPretendModeExtended',1,0)
  invoke(objSS,'Initialize','') %Initialise the Keithley board and object
end;
invoke(objSS,'SetMSPerSample',2); %Set StartExperiment routines’ sampling]]></screen></section><section><title>Collecting Responses</title><para>To collect responses in matlab using the button box add a code similar to this: </para><screen><![CDATA[ tic
 resp=0;
 gotresp=false;
   while toc<rt_window
      if (~gotresp)
         resp=bitand(30,invoke(objSS,'GetResponse'));
         if (resp==samekey || resp==diffkey)
            gotresp=true;
         end;
       end;
    end;]]></screen><para>This will collect the responses made by the subject during a pre-defined time interval (rt_window). You can also need to define which buttons the subject should press (in this example they are called samekey and diffkey). The codes returned by pressing the buttons are 28, 26, 22, 14 (i.e. when the right hand is placed on the button box and the subject used his index finger the code returned will be 28). </para><para>The <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/GetResponse#">GetResponse</ulink>() function will by default only return first four button presses. If there is a need to use more than 4 buttons one could use <ulink url="https://lsr-wiki-02.mrc-cbu.cam.ac.uk/imaging/ScannerSyncMatlab/imaging/GetResponseExtended#">GetResponseExtended</ulink>() or ReadPIOValue(). The example below uses the latter function and ignores responses 254 and 255, which relate to no-response events. </para><screen><![CDATA[ tic
 resp=0;
 gotresp=false;
 while toc<rt_window
    if (~gotresp)
       resp=invoke(objSS,'ReadPIOValue');
       if isempty(intersect([255,254],resp))
          gotresp=true;
       end;
    end;
 end;]]></screen></section><section><title>Collecting Response Times</title><para>To collect RTs you could try the following: </para><screen><![CDATA[resp=0;
gotresp=false;
respstarttime=invoke(objSS,'SSGetTimer');
tic
   while toc<rt_window
      if (~gotresp)
         resp=bitand(30,invoke(objSS,'GetResponse'));
         if (resp==samekey || resp==diffkey)
            rt=invoke(objSS,'SSGetTimer')-respstarttime; %or alternatively you can set rt=toc
            gotresp=true;
         end;
       end;
    end;]]></screen></section></section></article>