M1_20141113_B001_runstim.m 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. function runstim(Hnd) %#ok<FNDEF>
  2. global Par %global parameters
  3. global LPStat %das status values
  4. global STIM
  5. Par.TrainSession = false;
  6. % set to false for recording sessions !
  7. % it will allow more control over file-naming
  8. % files will get a default name if set to true (see line 52 and later)
  9. %Difficulty =================================================
  10. % CK20140128: Timing is taken from par file but overwritten by
  11. % CK20140128: values from the settings file in this runstim
  12. load('PAR_HICKEY.mat'); % load the default parameter-file
  13. % (maybe we can remove this later, but default Tracker relies on some settings)
  14. LOG.DefMonkeyName = 'Duvel'; % default monkey name used in creating a filename
  15. % can be overruled in filename when it's set through the dialog
  16. % Load settings file
  17. LOG.SettingsFile = 'HICKEY_SETTINGS_Duvel_20141029';
  18. eval(LOG.SettingsFile);
  19. LOG.SettingsFileFull = fullfile(pwd,[LOG.SettingsFile '.m']);
  20. Par.Trlcount = 0; %reset trialcount to 0
  21. % Every time you press run, Tracker will generate a unique list of stimuli
  22. % and conditions. If we continue the trialcount over repeated runs the
  23. % references to conditions won't work anymore. THis automatically means
  24. % that for every time you press run, there will be a separate log file
  25. % saved. There should also be a matching TDT file, so always stop and start
  26. % TDT and Tracker together.
  27. % Save stuff in this version
  28. cc=clock; % get time info from the system clock
  29. LOG.datestr=[sprintf('%04d',cc(1)) sprintf('%02d',cc(2)) ...
  30. sprintf('%02d',cc(3))]; % YYYYMMDD
  31. LOG.timestr=[sprintf('%02d',cc(4)) sprintf('%02d',cc(5)) ...
  32. sprintf('%02d',round(cc(6)))]; % HHMMSS
  33. % Create a random number in the largest range that can be encoded using 14 bits
  34. % We will send this as a word bit to TDT as an extra check when matching up
  35. % our TDT data-file and the Tracker-log. THis is in addition to consistent
  36. % filenaming.
  37. LOG.uniqueID = round(rand(1).*2^14);
  38. dasword(LOG.uniqueID);
  39. pause(.05); % make sure the word is received
  40. dasclearword();
  41. WordsSent=1; %keep track of how many words are sent so we back-check TDT against the log
  42. LOG.Words(WordsSent)=LOG.uniqueID; %collect all the words that are sent to TDT
  43. % Create a filename Monkeyname_YYYYMMDD_B#
  44. if Par.TrainSession
  45. fnLead = [LOG.DefMonkeyName '_' LOG.datestr '_TRAIN' ];
  46. % Training- and Recording sessions will be saved under different names
  47. else
  48. fnLead = [LOG.DefMonkeyName '_' LOG.datestr '_B' ];
  49. % this filename construction is convention for TDT as well
  50. end
  51. % look for log files with this date and find the lowest new block nr
  52. % will only check for files that follow the filename convention
  53. % MonkeyName_YYYYMMDD_Bx.mat (where x=blocknr)
  54. cd LOG; % go to log folder
  55. prevfiles=dir([fnLead '*']);
  56. % Assuming the last file has the highest blocknr
  57. % as it should when naming conventions are followed
  58. if ~isempty(prevfiles)
  59. CurrBlockNr = str2num(prevfiles(end).name(end))+1; %#ok<*ST2NM>
  60. else
  61. CurrBlockNr = 1;
  62. end
  63. cd ..
  64. % create an input dialog for setting the filename
  65. % suggest a default name based on the files that are already present
  66. LOG.FileNameSug = [fnLead sprintf('%03d',CurrBlockNr)];
  67. if ~Par.TrainSession
  68. LOG.FileName = inputdlg(...
  69. 'Start a new TDT block and set filename for Tracker-log consistently\n',...
  70. 'Filename',1,{LOG.FileNameSug});
  71. % take input name on 'ok', suggested name on 'cancel'
  72. if ~isempty(LOG.FileName)
  73. LOG.FileName = LOG.FileName{1};
  74. else
  75. LOG.FileName = LOG.FileNameSug;
  76. end
  77. else
  78. LOG.FileName = LOG.FileNameSug;
  79. end
  80. % Create an empty screen
  81. BG = STIM.BackCol; %background Color
  82. cgflip(BG(1), BG(2), BG(3)) %flip the videobuffer
  83. nf=1; %keep track of number of flips
  84. nfr=100; %refresh tracker every nfr frame flips
  85. %timing ====================================================
  86. % Timing from the Settings-file are used
  87. PREFIXT = STIM.PreFixT; % time allowed to initiate fixation
  88. FIXT = STIM.FixT; % duration to hold fixation before stimuli appear
  89. TARGT = STIM.KeepFixT; % Duration to hold fixation while stimuli are on the screen
  90. RACT = STIM.ReacT; % Time allowed to select a target after target onset
  91. SACCT= STIM.SaccT; % Allowed saccade time between leaving fixwin and entering targwin
  92. ISI = STIM.ISI; % interstimulus interval
  93. ISI_R = STIM.ISI_RAND; % max random addition to ISI
  94. ERRT = STIM.ErrT; % punishment addition to ISI after error trial
  95. %Stimulus information ======================================
  96. %Fixation dot size and location in pixels
  97. FixPosPix = STIM.FixPos*Par.PixPerDeg;
  98. px = FixPosPix(1); py = FixPosPix(2);
  99. Fsz = round(STIM.FixSz.*Par.PixPerDeg);
  100. TargSz = round(STIM.TarSz.*Par.PixPerDeg);
  101. %Windowing information =====================================
  102. % Info will be read from the settings file upon 'run'
  103. % but can be altered in the parameters tab
  104. Par.FixWdDeg = STIM.FixWinSz(1);
  105. Par.FixHtDeg = STIM.FixWinSz(2);
  106. Par.TargWdDeg = STIM.TarWinSz(1);
  107. Par.TargHtDeg = STIM.TarWinSz(2);
  108. %Make targets & distractors ----------------------
  109. targx = STIM.TarPos(:,1)'.*Par.PixPerDeg; % x-coordinates
  110. targy = STIM.TarPos(:,2)'.*Par.PixPerDeg; % y-coordinates
  111. %////YOUR STIMULATION CONTROL LOOP /////////////////////////////////
  112. Hit = 2;
  113. Par.ESC = false; %escape has not been pressed
  114. Par.Distcount = 0; %also count the number of times the distractor was selected
  115. TrialNr=0; % this is the index to rows in the triallist STIM.TrialList
  116. % it will increase when a new trial needs to be defined and stay the same
  117. % if a trial needs to be repeated. NB! this is not the same as the trial
  118. % count, which keep track of the number of started trials
  119. LOG.TotRew = 0; %keep track of earned total reward (excluding manual rewards)
  120. while ~Par.ESC
  121. %Pretrial
  122. %SETUP YOUR STIMULI FOR THIS TRIAL
  123. if Par.Drum && Hit ~= 2 %if drumming and this was an error trial
  124. %just redo with current settings
  125. else
  126. TrialNr=TrialNr+1;
  127. % CK20140128: This whole procedure is unflexible
  128. % CK20140128: I re-wrote it completely
  129. TrialTypeNo=STIM.TrialList(TrialNr,1);
  130. % be careful with referencing via Par.Trlcount
  131. % control window setup
  132. % 0 = fixation, 2 = target
  133. WIN=zeros(STIM.TarN+1,5);
  134. WIN(1,:)=[Par.PixPerDeg*STIM.FixPos(1),Par.PixPerDeg*STIM.FixPos(2),...
  135. Par.PixPerDeg*Par.FixWdDeg, Par.PixPerDeg*Par.FixHtDeg, 0];
  136. for i=1:STIM.TarN
  137. WIN(i+1,:)=[Par.PixPerDeg*STIM.TarPos(i,1),Par.PixPerDeg*STIM.TarPos(i,2), ...
  138. Par.PixPerDeg*Par.TargWdDeg, Par.PixPerDeg*Par.TargHtDeg, 1];
  139. end
  140. % which is the target?
  141. WIN(STIM.TrialTypes(TrialTypeNo,1)+1,5)=2;
  142. Par.WIN = WIN';
  143. end
  144. %/////////////////////////////////////////////////////////////////////
  145. %START THE TRIAL
  146. %set control window positions and dimensions
  147. refreshtracker(1) %for your control display
  148. SetWindowDas %for the dascard
  149. Abort = false; %whether subject has aborted before end of trial
  150. % sent trial number as word
  151. dasword(TrialNr);
  152. % TrialNr is the row index in STIM.TrialList for the prepared
  153. % next trial. In this row STIM.TrialList defines the stimuus array as:
  154. % # STIM.TrialList(TrialNr,1) = TrialType, which in turn indexes a
  155. % row in STIM.TrialTypes where c1 is target location, c2 is target
  156. % shape (1=circle, 2=square), and c3 is distractor location
  157. % # STIM.TrialList(TrialNr,2) = Index to STIM.ColSchemes that
  158. % defines the RGB values for target, distractor and non-targets
  159. % # STIM.TrialList(TrialNr,3) = Index to STIM.RewardValues to
  160. % dissociate between high and low rewarded trials.
  161. WordsSent=WordsSent+1;
  162. LOG.Words(WordsSent)=TrialNr;
  163. %///////// EVENT 0 START FIXATING//////////////////////////////////////
  164. cgellipse(px,py,Fsz,Fsz,STIM.FixCol_NoGo,'f') %the red fixation dot on the screen
  165. cgflip(BG(1), BG(2), BG(3))
  166. nf=nf+1;
  167. dasreset(0); %test enter fix window
  168. % 0 enter fix window
  169. % 1 leave fix window
  170. % 2 enter target window
  171. %subject has to start fixating central dot
  172. Par.SetZero = false; %set key to false to remove previous presses
  173. %Par.Updatxy = 1; %centering key is enabled
  174. Time = 1;
  175. Hit = 0;
  176. while Time < PREFIXT && Hit == 0
  177. %dasrun(5)
  178. [Hit Time] = DasCheck; %#ok<*NCOMMA> %retrieve position values and plot on Control display
  179. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  180. end
  181. %disp( [num2str(hitbreak) ' enter ' num2str(toc)])
  182. %///////// EVENT 1 KEEP FIXATING or REDO ////////////////////////////////////
  183. if Hit ~= 0 %subjects eyes are in fixation window keep fixating for FIX time
  184. dasreset(1); %set test parameters for exiting fix window
  185. Time = 1;
  186. Hit = 0;
  187. while Time < FIXT && Hit== 0
  188. %Check for 10 ms
  189. %dasrun(5)
  190. [Hit Time] = DasCheck; %retrieve eyechannel buffer and events, plot eye motion,
  191. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  192. end
  193. if Hit ~= 0 %eye has left fixation to early
  194. %possibly due to eye overshoot, give another chance
  195. dasreset(0);
  196. Time = 1;
  197. Hit = 0;
  198. while Time < PREFIXT && Hit == 0
  199. %dasrun(5)
  200. [Hit Time] = DasCheck; %retrieve position values and plot on Control display
  201. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  202. end
  203. if Hit ~= 0 %subjects eyes are in fixation window keep fixating for FIX time
  204. dasreset( 1); %test for exiting fix window
  205. Time = 1;
  206. Hit = 0;
  207. while Time < FIXT && Hit == 0
  208. %Check for 10 ms
  209. % pause(0.005)
  210. %dasrun(5)
  211. [Hit Time] = DasCheck;
  212. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  213. end
  214. else
  215. Hit = -1; %the subject did not fixate
  216. end
  217. end
  218. else
  219. Hit = -1; %the subject did not fixate
  220. end
  221. % LPP = dasrun 10);
  222. % setdatatype(LPP, 'int32Ptr', 2, 1)
  223. % display(LPP.Value)
  224. %///////// EVENT 2 DISPLAY STIMULUS //////////////////////////////////////
  225. if Hit == 0 %subject kept fixation, display stimulus
  226. Par.Trlcount = Par.Trlcount + 1; %counts total number of trials for this session
  227. % a trial is only counted when prefix is fullfilled
  228. % as long as no stimulus is shown, it's still the same trial
  229. % since this trial is started and the trial count updated:
  230. % log extensive info for this trial
  231. LOG.Trial(Par.Trlcount).TrialNr = TrialNr;
  232. LOG.Trial(Par.Trlcount).TrialCnt = Par.Trlcount;
  233. LOG.Trial(Par.Trlcount).TrialTypeNo = TrialTypeNo;
  234. LOG.Trial(Par.Trlcount).WordsSent = WordsSent;
  235. LOG.Trial(Par.Trlcount).LastWord = LOG.Words(WordsSent);
  236. LOG.Trial(Par.Trlcount).TarPos = STIM.TrialTypes(STIM.TrialList(TrialNr,1),1);
  237. LOG.Trial(Par.Trlcount).TarShape = STIM.TrialTypes(STIM.TrialList(TrialNr,1),2);
  238. LOG.Trial(Par.Trlcount).DistPos = STIM.TrialTypes(STIM.TrialList(TrialNr,1),3);
  239. LOG.Trial(Par.Trlcount).ColScheme = STIM.TrialList(TrialNr,2);
  240. LOG.Trial(Par.Trlcount).RewValue = STIM.RewardValues(STIM.TrialList(TrialNr,3));
  241. % draw stimuli
  242. for s = 1:STIM.TarN
  243. if s==STIM.TrialTypes(TrialTypeNo,1) %this is the target
  244. if STIM.TrialTypes(TrialTypeNo,2) == 1 % target is circle
  245. cgellipse(targx(s),targy(s),...
  246. TargSz,TargSz,STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColCorr,'f');
  247. else % target is rect
  248. if STIM.RectRndCornerFract == 0
  249. cgrect(targx(s),targy(s),...
  250. sqrt(pi.*((TargSz/2).^2)),sqrt(pi.*((TargSz/2).^2)),...
  251. STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColCorr);
  252. else
  253. % draw 4 small circles on the corners and fill the
  254. % middle area in with rectangles
  255. cx = targx(s);
  256. cy = targy(s);
  257. sidesize = sqrt(pi.*((TargSz/2).^2));
  258. cornrad = (sidesize*STIM.RectRndCornerFract)/2;
  259. ccircx = [cx-sidesize/2+cornrad;cx-sidesize/2+cornrad;...
  260. cx+sidesize/2-cornrad;cx+sidesize/2-cornrad];
  261. ccircy = [cy+sidesize/2-cornrad;cy-sidesize/2+cornrad;...
  262. cy-sidesize/2+cornrad;cy+sidesize/2-cornrad];
  263. ccircw = [cornrad; cornrad; cornrad; cornrad].*2 ;
  264. ccirch = ccircw ;
  265. % draw
  266. cgrect(ccircx,ccircy,ccircw,ccirch,[STIM.BackCol;STIM.BackCol;STIM.BackCol;STIM.BackCol]);
  267. tcol=STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColCorr;
  268. cgellipse(ccircx,ccircy,ccircw,ccirch,[tcol;tcol;tcol;tcol],'f');
  269. cgrect([cx;cx],[cy,cy],[sidesize-(2*cornrad)+1; sidesize+1],...
  270. [sidesize+1; sidesize-(2*cornrad)+1],[tcol;tcol]);
  271. end
  272. end
  273. elseif s==STIM.TrialTypes(TrialTypeNo,3) %this is the salient non-target
  274. if STIM.TrialTypes(TrialTypeNo,2) == 1 % target is circle
  275. if STIM.RectRndCornerFract == 0
  276. cgrect(targx(s),targy(s),...
  277. sqrt(pi.*((TargSz/2).^2)),sqrt(pi.*((TargSz/2).^2)),...
  278. STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_Sal);
  279. else
  280. % draw 4 small circles on the corners and fill the
  281. % middle area in with rectangles
  282. cx = targx(s);
  283. cy = targy(s);
  284. sidesize = sqrt(pi.*((TargSz/2).^2));
  285. cornrad = (sidesize*STIM.RectRndCornerFract)/2;
  286. ccircx = [cx-sidesize/2+cornrad;cx-sidesize/2+cornrad;...
  287. cx+sidesize/2-cornrad;cx+sidesize/2-cornrad];
  288. ccircy = [cy+sidesize/2-cornrad;cy-sidesize/2+cornrad;...
  289. cy-sidesize/2+cornrad;cy+sidesize/2-cornrad];
  290. ccircw = [cornrad; cornrad; cornrad; cornrad].*2 ;
  291. ccirch = ccircw ;
  292. % draw
  293. cgrect(ccircx,ccircy,ccircw,ccirch,[STIM.BackCol;STIM.BackCol;STIM.BackCol;STIM.BackCol]);
  294. tcol=STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_Sal;
  295. cgellipse(ccircx,ccircy,ccircw,ccirch,[tcol;tcol;tcol;tcol],'f');
  296. cgrect([cx;cx],[cy,cy],[sidesize-(2*cornrad)+1; sidesize+1],...
  297. [sidesize+1; sidesize-(2*cornrad)+1],[tcol;tcol]);
  298. end
  299. else % target is rect
  300. cgellipse(targx(s),targy(s),...
  301. TargSz,TargSz,STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_Sal,'f');
  302. end
  303. else % normal non-target
  304. if STIM.TrialTypes(TrialTypeNo,2) == 1 % target is circle
  305. if STIM.RectRndCornerFract == 0
  306. cgrect(targx(s),targy(s),...
  307. sqrt(pi.*((TargSz/2).^2)),sqrt(pi.*((TargSz/2).^2)),...
  308. STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_NonSal);
  309. else
  310. % draw 4 small circles on the corners and fill the
  311. % middle area in with rectangles
  312. cx = targx(s);
  313. cy = targy(s);
  314. sidesize = sqrt(pi.*((TargSz/2).^2));
  315. cornrad = (sidesize*STIM.RectRndCornerFract)/2;
  316. ccircx = [cx-sidesize/2+cornrad;cx-sidesize/2+cornrad;...
  317. cx+sidesize/2-cornrad;cx+sidesize/2-cornrad];
  318. ccircy = [cy+sidesize/2-cornrad;cy-sidesize/2+cornrad;...
  319. cy-sidesize/2+cornrad;cy+sidesize/2-cornrad];
  320. ccircw = [cornrad; cornrad; cornrad; cornrad].*2 ;
  321. ccirch = ccircw ;
  322. % draw
  323. cgrect(ccircx,ccircy,ccircw,ccirch,[STIM.BackCol;STIM.BackCol;STIM.BackCol;STIM.BackCol]);
  324. tcol=STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_NonSal;
  325. cgellipse(ccircx,ccircy,ccircw,ccirch,[tcol;tcol;tcol;tcol],'f');
  326. cgrect([cx;cx],[cy,cy],[sidesize-(2*cornrad)+1; sidesize+1],...
  327. [sidesize+1; sidesize-(2*cornrad)+1],[tcol;tcol]);
  328. end
  329. else % target is rect
  330. cgellipse(targx(s),targy(s),...
  331. TargSz,TargSz,STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_NonSal,'f');
  332. end
  333. end
  334. end
  335. cgellipse(px,py,Fsz,Fsz,STIM.FixCol_NoGo,'f') %the red fixation dot on the screen
  336. FO = cgflip(BG(1), BG(2), BG(3));
  337. nf=nf+1;
  338. dasbit(Par.StimB, 1); % set the stim channel in TDT to 1 to allow stimulus onset reconstruction
  339. %dasbit( Par.MicroB, 1);
  340. tic %measure onset to
  341. %..............................................................
  342. dasreset(1); %test for exiting fix window
  343. refreshtracker(2)
  344. Time = 0;
  345. %StimFlg = true;
  346. while Time < TARGT && Hit == 0 %Keep fixating till target onset
  347. if TARGT - Time < 5
  348. %dasrun(5)
  349. %don't plot any more, so we immediately break from loop
  350. Hit = LPStat(2);
  351. break
  352. else
  353. %Check for 5 ms
  354. %dasrun(5)
  355. %get hit time and plot eyemotion
  356. [Hit Time] = DasCheck;
  357. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  358. end
  359. end
  360. % if 0 % Never executed? For debugging? [CK]
  361. % %..............................................................
  362. % %%%%%%
  363. % %how much time(ms) do we have left till target onset???
  364. % delay = floor(TARGT + 5 * FLtime - toc*1000 - 5); %hold up calling the next flip
  365. % if delay > 0
  366. % dasrun(delay)
  367. % Hit = LPStat(2); %don't wast time!!!! on updating the screen
  368. % end
  369. % end
  370. %///////// EVENT 3 TARGET ONSET, REACTION TIME%%//////////////////////////////////////
  371. if Hit == 0 %subject kept fixation, subject may make an eye movement
  372. %Draw targets
  373. for s = 1:STIM.TarN
  374. if s==STIM.TrialTypes(TrialTypeNo,1) %this is the target
  375. if STIM.TrialTypes(TrialTypeNo,2) == 1 % target is circle
  376. cgellipse(targx(s),targy(s),...
  377. TargSz,TargSz,STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColCorr,'f');
  378. else % target is rect
  379. if STIM.RectRndCornerFract == 0
  380. cgrect(targx(s),targy(s),...
  381. sqrt(pi.*((TargSz/2).^2)),sqrt(pi.*((TargSz/2).^2)),...
  382. STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColCorr);
  383. else
  384. % draw 4 small circles on the corners and fill the
  385. % middle area in with rectangles
  386. cx = targx(s);
  387. cy = targy(s);
  388. sidesize = sqrt(pi.*((TargSz/2).^2));
  389. cornrad = (sidesize*STIM.RectRndCornerFract)/2;
  390. ccircx = [cx-sidesize/2+cornrad;cx-sidesize/2+cornrad;...
  391. cx+sidesize/2-cornrad;cx+sidesize/2-cornrad];
  392. ccircy = [cy+sidesize/2-cornrad;cy-sidesize/2+cornrad;...
  393. cy-sidesize/2+cornrad;cy+sidesize/2-cornrad];
  394. ccircw = [cornrad; cornrad; cornrad; cornrad].*2 ;
  395. ccirch = ccircw ;
  396. % draw
  397. cgrect(ccircx,ccircy,ccircw,ccirch,[STIM.BackCol;STIM.BackCol;STIM.BackCol;STIM.BackCol]);
  398. tcol=STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColCorr;
  399. cgellipse(ccircx,ccircy,ccircw,ccirch,[tcol;tcol;tcol;tcol],'f');
  400. cgrect([cx;cx],[cy,cy],[sidesize-(2*cornrad)+1; sidesize+1],...
  401. [sidesize+1; sidesize-(2*cornrad)+1],[tcol;tcol]);
  402. end
  403. end
  404. elseif s==STIM.TrialTypes(TrialTypeNo,3) %this is the salient non-target
  405. if STIM.TrialTypes(TrialTypeNo,2) == 1 % target is circle
  406. if STIM.RectRndCornerFract == 0
  407. cgrect(targx(s),targy(s),...
  408. sqrt(pi.*((TargSz/2).^2)),sqrt(pi.*((TargSz/2).^2)),...
  409. STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_Sal);
  410. else
  411. % draw 4 small circles on the corners and fill the
  412. % middle area in with rectangles
  413. cx = targx(s);
  414. cy = targy(s);
  415. sidesize = sqrt(pi.*((TargSz/2).^2));
  416. cornrad = (sidesize*STIM.RectRndCornerFract)/2;
  417. ccircx = [cx-sidesize/2+cornrad;cx-sidesize/2+cornrad;...
  418. cx+sidesize/2-cornrad;cx+sidesize/2-cornrad];
  419. ccircy = [cy+sidesize/2-cornrad;cy-sidesize/2+cornrad;...
  420. cy-sidesize/2+cornrad;cy+sidesize/2-cornrad];
  421. ccircw = [cornrad; cornrad; cornrad; cornrad].*2 ;
  422. ccirch = ccircw ;
  423. % draw
  424. cgrect(ccircx,ccircy,ccircw,ccirch,[STIM.BackCol;STIM.BackCol;STIM.BackCol;STIM.BackCol]);
  425. tcol=STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_Sal;
  426. cgellipse(ccircx,ccircy,ccircw,ccirch,[tcol;tcol;tcol;tcol],'f');
  427. cgrect([cx;cx],[cy,cy],[sidesize-(2*cornrad)+1; sidesize+1],...
  428. [sidesize+1; sidesize-(2*cornrad)+1],[tcol;tcol]);
  429. end
  430. else % target is rect
  431. cgellipse(targx(s),targy(s),...
  432. TargSz,TargSz,STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_Sal,'f');
  433. end
  434. else % normal non-target
  435. if STIM.TrialTypes(TrialTypeNo,2) == 1 % target is circle
  436. if STIM.RectRndCornerFract == 0
  437. cgrect(targx(s),targy(s),...
  438. sqrt(pi.*((TargSz/2).^2)),sqrt(pi.*((TargSz/2).^2)),...
  439. STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_NonSal);
  440. else
  441. % draw 4 small circles on the corners and fill the
  442. % middle area in with rectangles
  443. cx = targx(s);
  444. cy = targy(s);
  445. sidesize = sqrt(pi.*((TargSz/2).^2));
  446. cornrad = (sidesize*STIM.RectRndCornerFract)/2;
  447. ccircx = [cx-sidesize/2+cornrad;cx-sidesize/2+cornrad;...
  448. cx+sidesize/2-cornrad;cx+sidesize/2-cornrad];
  449. ccircy = [cy+sidesize/2-cornrad;cy-sidesize/2+cornrad;...
  450. cy-sidesize/2+cornrad;cy+sidesize/2-cornrad];
  451. ccircw = [cornrad; cornrad; cornrad; cornrad].*2 ;
  452. ccirch = ccircw ;
  453. % draw
  454. cgrect(ccircx,ccircy,ccircw,ccirch,[STIM.BackCol;STIM.BackCol;STIM.BackCol;STIM.BackCol]);
  455. tcol=STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_NonSal;
  456. cgellipse(ccircx,ccircy,ccircw,ccirch,[tcol;tcol;tcol;tcol],'f');
  457. cgrect([cx;cx],[cy,cy],[sidesize-(2*cornrad)+1; sidesize+1],...
  458. [sidesize+1; sidesize-(2*cornrad)+1],[tcol;tcol]);
  459. end
  460. else % target is rect
  461. cgellipse(targx(s),targy(s),...
  462. TargSz,TargSz,STIM.ColSchemes(STIM.TrialList(TrialNr,2)).TargColErr_NonSal,'f');
  463. end
  464. end
  465. end
  466. cgellipse(px,py,Fsz,Fsz,STIM.FixCol_Go,'f') %the green fixation dot on the screen
  467. FS = cgflip(BG(1), BG(2), BG(3));
  468. nf=nf+1;
  469. LOG.Trial(Par.Trlcount).StimOnset = FO;
  470. LOG.Trial(Par.Trlcount).TargOnset = FS;
  471. LOG.Trial(Par.Trlcount).StimTarDur = FS - FO; % log time between stim and targ onset
  472. dasbit(Par.TargetB, 1); % set the target channel in TDT to 1 to allow target onset reconstruction
  473. dasreset(2); %check target window enter
  474. refreshtracker(3) %set fix point to green
  475. Time = 0;
  476. while Time < RACT && Hit <= 0 %RACT = time to respond (reaction time)
  477. %Check for 5 ms
  478. %dasrun(5)
  479. [Hit Time] = DasCheck;
  480. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  481. end
  482. %Hit % don't output this to cmd
  483. else
  484. Abort = true;
  485. end
  486. %END EVENT 3
  487. else
  488. Abort = true;
  489. end
  490. %END EVENT 2
  491. %///////// POSTTRIAL AND REWARD //////////////////////////////////////
  492. if Hit ~= 0 && ~Abort %has entered a target window (false or correct)
  493. if Par.Mouserun
  494. HP = line('XData', Par.ZOOM * (LPStat(3) + Par.MOff(1)), 'YData', Par.ZOOM * (LPStat(4) + Par.MOff(2)), 'EraseMode','none');
  495. else
  496. HP = line('XData', Par.ZOOM * LPStat(3), 'YData', Par.ZOOM * LPStat(4), 'EraseMode','none');
  497. end
  498. set(HP, 'Marker', '+', 'MarkerSize', 20, 'MarkerEdgeColor', 'm')
  499. if Hit == 2 && LPStat(6) < SACCT %correct target within max allowed saccade time >> give juice
  500. dasbit( Par.CorrectB, 1); % set the Correct channel in TDT to 1
  501. dasbit( Par.RewardB, 1); % set the Reward channel in TDT to 1
  502. dasjuice(5); % open reward valve
  503. Par.Corrcount = Par.Corrcount + 1; %log correct trials
  504. % beep
  505. TrialStatus='Target';
  506. % find out how much reward should be given and give it
  507. if STIM.UseSpecRew
  508. RewTime = STIM.RewardValues(STIM.TrialList(TrialNr,3));
  509. LOG.TotRew = LOG.TotRew+RewTime;
  510. pause(RewTime) %RewardTime is in seconds
  511. else
  512. pause(Par.RewardTime) %RewardTime is in seconds
  513. LOG.TotRew = LOG.TotRew+Par.RewardTime;
  514. end
  515. dasjuice(0.0); % switch off reward
  516. dasbit( Par.RewardB, 0); % set the Reward channel in TDT to 0
  517. % log which target was selected
  518. LOG.Trial(Par.Trlcount).TarChoice=LOG.Trial(Par.Trlcount).TarPos;
  519. elseif Hit == 1 && LPStat(6) < SACCT
  520. dasbit( Par.ErrorB, 1);
  521. Par.Errcount = Par.Errcount + 1;
  522. % what kind of error?
  523. % check x,y endpoints against target windows
  524. % these are the x and y endpoints of the eye data
  525. xE=LPStat(3);
  526. yE=LPStat(4);
  527. %targx is a column of target x positions
  528. %targy is a column of target y positions
  529. % calculate the distance from the eye-endpoint to all targets
  530. EyeDistFromTar = sqrt((targx-xE).^2+(targy-yE).^2);
  531. % find the closest target (should be the one that is selected)
  532. SelTar=find(EyeDistFromTar==min(EyeDistFromTar),1,'first');
  533. % this procedure fails if target windows overlap
  534. % which they shouldn't anyway
  535. % log which target was selected
  536. LOG.Trial(Par.Trlcount).TarChoice=SelTar;
  537. % determine the status of the chosen target
  538. if SelTar==STIM.TrialTypes(TrialTypeNo,3)
  539. % salient distractor selected
  540. TrialStatus='Distractor';
  541. Par.Distcount=Par.Distcount+1;
  542. else
  543. %in wrong target window
  544. TrialStatus='Nontarget';
  545. end
  546. elseif Hit ~= 0 && LPStat(6) >= SACCT % too slow
  547. TrialStatus='SaccadeTooSlow';
  548. end
  549. %keep following eye motion to plot complete saccade
  550. for i = 1:10 %keep targoff for 50ms
  551. %dasrun(5) %not time critical, add some time to follow eyes
  552. %dasrun 5);
  553. DasCheck; %keep following eye motion
  554. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  555. end
  556. % log some behavioral info
  557. LOG.Trial(Par.Trlcount).ReactTime = LPStat(5);
  558. LOG.Trial(Par.Trlcount).SaccTime = LPStat(6);
  559. LOG.Trial(Par.Trlcount).HitPos = [LPStat(3) LPStat(4)];
  560. LOG.Trial(Par.Trlcount).Status = TrialStatus;
  561. LOG.Trial(Par.Trlcount).TotRew = LOG.TotRew;
  562. %output some info to cmd
  563. % trial nr and status
  564. fprintf(['Trial ' num2str(Par.Trlcount) ': ' TrialStatus '\n']);
  565. % reaction time (RT), saccade time(ST), and Total reward (TR) until now
  566. fprintf(['RT: ' num2str(LPStat(5)) ...
  567. ' ST: ' num2str(LPStat(6)) ...
  568. ' TR: ' num2str(LOG.TotRew) '\n\n']);
  569. elseif Par.Trlcount>0 && ~Abort % trial was not aborted but no target was selected in time
  570. TrialStatus='NoHit';
  571. % log some behavioral info
  572. LOG.Trial(Par.Trlcount).ReactTime = [];
  573. LOG.Trial(Par.Trlcount).SaccTime = [];
  574. LOG.Trial(Par.Trlcount).HitPos = [];
  575. LOG.Trial(Par.Trlcount).Status = TrialStatus;
  576. LOG.Trial(Par.Trlcount).TotRew = LOG.TotRew;
  577. %output some info to cmd
  578. fprintf(['Trial ' num2str(Par.Trlcount) ': ' TrialStatus '\n']);
  579. fprintf(['RT: ' num2str(LPStat(5)) ...
  580. ' ST: ' num2str(LPStat(6)) ...
  581. ' TR: ' num2str(LOG.TotRew) '\n\n']);
  582. elseif Par.Trlcount>0 && Abort % trial was started but aborted
  583. TrialStatus='Aborted';
  584. % log some behavioral info
  585. LOG.Trial(Par.Trlcount).ReactTime = [];
  586. LOG.Trial(Par.Trlcount).SaccTime = [];
  587. LOG.Trial(Par.Trlcount).HitPos = [];
  588. LOG.Trial(Par.Trlcount).Status = TrialStatus;
  589. LOG.Trial(Par.Trlcount).TotRew = LOG.TotRew;
  590. end
  591. if Hit ~= 2 %error response
  592. %add pause when subject makes error
  593. for i = 1:round(ERRT/5) %keep targoff for Times.Err ms
  594. % pause(0.005)
  595. %dasrun(5)
  596. DasCheck;
  597. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  598. end
  599. end %Times.Err is in ms
  600. [Hit Lasttime] = DasCheck;
  601. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  602. %///////////////////////INTERTRIAL AND CLEANUP
  603. %reset all bits to null
  604. for i = [0 1 2 3 4 5 6 7] %Error, Stim, Saccade, Trial, Correct,
  605. dasbit( i, 0);
  606. end
  607. dasclearword();
  608. SCNT = {'TRIALS'};
  609. SCNT(2) = { ['N: ' num2str(Par.Trlcount) ]}; % n trials
  610. SCNT(3) = { ['C: ' num2str(Par.Corrcount) ] }; % n correct
  611. SCNT(4) = { ['E: ' num2str(Par.Errcount) ] }; % n error
  612. SCNT(5) = { ['D: ' num2str(Par.Distcount) ] }; % n distractor
  613. set(Hnd(1), 'String', SCNT ) %display updated numbers in GUI
  614. SD = dasgetnoise();
  615. SD = SD./Par.PixPerDeg;
  616. set(Hnd(2), 'String', SD )
  617. cgpencol(BG(1), BG(2), BG(3)) %clear background before flipping
  618. cgrect
  619. cgflip(BG(1), BG(2), BG(3))
  620. nf=nf+1;
  621. %pause( Times.InterTrial/1000 ) %pause is called with seconds
  622. %Times.InterTrial is in ms
  623. Time = Lasttime;
  624. while Time < ISI + ISI_R*rand(1) + ERRT
  625. % pause(0.005)
  626. %dasrun(5)
  627. [hit Time] = DasCheck; %#ok<ASGLU>
  628. if mod(nf,nfr)==0; refreshtracker(1); end %keep eye-position line short
  629. end
  630. end %WHILE_NOT_ESCAPED%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  631. %% Save log file ===============================
  632. cd LOG;
  633. % create a folder for this run
  634. warning off; %#ok<*WNOFF>
  635. mkdir(LOG.FileName);
  636. cd(LOG.FileName);
  637. % the generated parameters in a log-file
  638. save(LOG.FileName,'LOG','Par','STIM','-v7.3');
  639. % a copy of this runstim
  640. fn=[LOG.FileName '_runstim.m'];
  641. cfn=[mfilename('fullpath') '.m'];
  642. copyfile(cfn,fn);
  643. % a copy of the settings file
  644. copyfile(LOG.SettingsFileFull,[LOG.FileName '_settings.m']);
  645. cd ..
  646. cd ..
  647. % backup under unique time name in case you accidentally overwrite
  648. mkdir('REDUNDANT_LOG');
  649. warning on; %#ok<*WNON>
  650. cd 'REDUNDANT_LOG';
  651. save(['DATA_' LOG.datestr '_' LOG.timestr],'LOG','Par','STIM','-v7.3');
  652. copyfile(cfn,['Runstim_' LOG.datestr '_' LOG.timestr '.m']);
  653. copyfile(LOG.SettingsFileFull,['Settings_' LOG.datestr '_' LOG.timestr '.m']);
  654. cd ..