ISP_MoBi_sequence.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. function [forces]=ISP_MoBi_sequence(contraction_task, data_subject, volume, forces, bl)
  2. % the script is identical to ISP_MoBi_sequence_MEP with the exception of no
  3. % force estimation and only MEP blocks (so there are only TEP blocks).
  4. % refer to the ISP_MoBi_sequence_MEP for comments
  5. max_force_left = forces.max_force_left;
  6. max_force_right = forces.max_force_right;
  7. cd 'C:\Users\neuro\Desktop\script_mobi_da_commentare'
  8. sca;
  9. close all;
  10. %%
  11. % consider left hand state
  12. switch contraction_task{1,2} % force as a proportion of the outer circle...
  13. case 'Contratta'
  14. LEFT = [0.2 0.4];
  15. istruzione_sx = 'Mantieni\nil cerchietto\nverde';
  16. case 'Rilassata'
  17. LEFT = [0 0.01];
  18. istruzione_sx = 'Rilassa'
  19. end
  20. % consider right hand state
  21. switch contraction_task{1,3}
  22. case 'Contratta'
  23. RIGHT = [0.2 0.4];
  24. istruzione_dx = 'Mantieni\nil cerchietto\nverde';
  25. case 'Rilassata'
  26. RIGHT = [0.0 0.01];
  27. istruzione_dx = 'Rilassa'
  28. end
  29. %% specify trigger number
  30. switch contraction_task{1,1}
  31. case 'Mono_AP'
  32. TMS_trigger = 3;
  33. case 'Mono_PA'
  34. TMS_trigger = 5;
  35. case 'Mono_LM'
  36. TMS_trigger = 7;
  37. case 'Bi_PA_contracted'
  38. TMS_trigger = 160;
  39. case 'Bi_AP'
  40. TMS_trigger = 130;
  41. case 'Bi_PA'
  42. TMS_trigger = 150;
  43. case 'Bi_LM'
  44. TMS_trigger = 170;
  45. end
  46. %%
  47. % as a proportion to y axis...
  48. outer_dimension = 0.4;
  49. inner_dimensionL = LEFT(1);
  50. middle_dimensionL = LEFT(2);
  51. inner_dimensionR = RIGHT(1);
  52. middle_dimensionR = RIGHT(2);
  53. inner_force_limit_propL = inner_dimensionL;
  54. outer_force_limit_propL = middle_dimensionL;
  55. inner_force_limit_propR = inner_dimensionR;
  56. outer_force_limit_propR = middle_dimensionR;
  57. outer_circle_color = [1 1 1];%[0 0 0];%
  58. middle_circle_color = [0.5 0.5 0.5];
  59. inner_circle_color = [0 0 0];
  60. variable_circle_colorL = [0 1 0];
  61. variable_circle_colorR = [0 1 0];
  62. variable_circle_thickness = 5;
  63. force_steps = 500;
  64. num_trials = 40;
  65. estimation_time = 10; %secs
  66. time_x_avg = 0.5; % secs
  67. %% DO you want to tinker with small screen?
  68. tinker = 0;
  69. HideCursor
  70. %% SCREEN SETTING
  71. [window, misure_schermo, screenNum, CenterX, CenterY, ifi] = MoBi_Screen_Settings_Brescia(tinker);
  72. %MoBi_Screen_Settings_Brescia;
  73. %proporzioni_schermo = misure_schermo(4)/misure_schermo(3);
  74. %%
  75. delete(instrfindall);
  76. clear s
  77. %Set up the serial port
  78. s = serial('COM5');
  79. set(s, 'BaudRate', 115200); % set BaudRate to 115200 (as in Arduino!!!!!)
  80. % open it
  81. fopen(s);
  82. WaitSecs(2);
  83. for d = 1:2
  84. MoBi_scrittura(s);
  85. end
  86. %%
  87. [ifi_af, ifi_as, ifi_nf, ifi_ns] = MoBI_frames_Brescia(ifi, ifi);
  88. [onesec_af, onesec_as, onesec_nf, onesec_ns] = MoBI_frames_Brescia(1, ifi);
  89. %% parallel port init
  90. ioObj = io64;
  91. status = io64(ioObj);
  92. address = hex2dec('DFB8');
  93. io64(ioObj, address ,0);
  94. %%
  95. delay_after_TMS = 0.4;
  96. TMS_extremes = [4.4 6.4]-delay_after_TMS;
  97. TMS_interval_tmp = (TMS_extremes(2) - TMS_extremes(1))*rand(num_trials,1)+TMS_extremes(1);
  98. [TMS_int_af, TMS_int_as, TMS_int_nf, TMS_int_ns] = MoBI_frames_Brescia(TMS_interval_tmp, ifi);
  99. %% the systems outputs a "-1/force" function
  100. % --> set the max of the function to max_force and the min to 0
  101. % in steps of 500 values of forces (this can be changed)
  102. x = linspace(1,10,force_steps);
  103. % produce the shape
  104. funz_tmp = (-1./x)+1;
  105. % the shape is morphed so that it goes from 0 to 1 and multuplied by
  106. % max_force
  107. funzL = (funz_tmp./(funz_tmp(end)))*max_force_left;
  108. funzR = (funz_tmp./(funz_tmp(end)))*max_force_right;
  109. % this is the linear function with range [0 max_force] which will be
  110. % helpful afterwards to linearize the voltage read
  111. linearizeL = linspace(0, max_force_left, force_steps);
  112. linearizeR = linspace(0, max_force_right, force_steps);
  113. %% SET ALL THE VISUALS on the LEFT
  114. % proportion with respect to the entire screen
  115. set_proportion_of_diameter_outer_circleL = outer_dimension;
  116. prop_diameter_outer_circleL = set_proportion_of_diameter_outer_circleL;
  117. % transform proportions to actual pixels --> we get dimaeter of outer
  118. % circle in pixels
  119. dimensions_outer_circleL = MoBi_prop2dim(misure_schermo, 0, prop_diameter_outer_circleL);
  120. % same procedure for inner and middle circle calculated on the basis of the outer
  121. % circle
  122. prop_diameter_inner_circleL = inner_dimensionL*prop_diameter_outer_circleL;
  123. dimensions_inner_circleL = MoBi_prop2dim(misure_schermo, 0, prop_diameter_inner_circleL);
  124. prop_diameter_middle_circleL = middle_dimensionL*prop_diameter_outer_circleL;
  125. dimensions_middle_circleL = MoBi_prop2dim(misure_schermo, 0, prop_diameter_middle_circleL);
  126. %% generate a structure for the LEFT circle with the features of the circle as fields
  127. % we have two objsect now...place the left one on the first quarter of the
  128. % screen length, the other on the last quarter
  129. first_quarter = 3*misure_schermo(3)/8;
  130. last_quarter = 5*misure_schermo(3)/8;
  131. % ...color
  132. ObL.outer_circle.color = outer_circle_color;
  133. % ...diameter
  134. ObL.outer_circle.dimension = [0 0 dimensions_outer_circleL(2) dimensions_outer_circleL(2)]
  135. % center position on the screen
  136. baseRect_outer = [ObL.outer_circle.dimension];
  137. % place in the first quarter
  138. ObL.outer_circle.dimension = CenterRectOnPoint(baseRect_outer, first_quarter, misure_schermo(4)/2);
  139. % same goes for the other circles
  140. ObL.inner_circle.color = inner_circle_color;
  141. ObL.inner_circle.dimension = [0 0 dimensions_inner_circleL(2) dimensions_inner_circleL(2)]
  142. baseRect_inner = [ObL.inner_circle.dimension];
  143. % place in the first quarter
  144. ObL.inner_circle.dimension = CenterRectOnPoint(baseRect_inner, first_quarter, misure_schermo(4)/2);
  145. ObL.middle_circle.color = middle_circle_color;
  146. ObL.middle_circle.dimension = [0 0 dimensions_middle_circleL(2) dimensions_middle_circleL(2)]
  147. baseRect_middle = [ObL.middle_circle.dimension];
  148. % place in the first quarter
  149. ObL.middle_circle.dimension = CenterRectOnPoint(baseRect_middle, first_quarter, misure_schermo(4)/2);
  150. %% SET ALL THE VISUALS on the RIGHT
  151. % proportion with respect to the entire screen
  152. set_proportion_of_diameter_outer_circleR = outer_dimension;
  153. prop_diameter_outer_circleR = [set_proportion_of_diameter_outer_circleR];
  154. % transform proportions to actual pixels --> we get dimaeter of outer
  155. % circle in pixels
  156. dimensions_outer_circleR = MoBi_prop2dim(misure_schermo, 0, prop_diameter_outer_circleR);
  157. % same procedure for inner and middle circle calculated on the basis of the outer
  158. % circle
  159. prop_diameter_inner_circleR = inner_dimensionR*prop_diameter_outer_circleR;
  160. dimensions_inner_circleR = MoBi_prop2dim(misure_schermo, 0, prop_diameter_inner_circleR);
  161. prop_diameter_middle_circleR = middle_dimensionR*prop_diameter_outer_circleR;
  162. dimensions_middle_circleR = MoBi_prop2dim(misure_schermo, 0, prop_diameter_middle_circleR);
  163. %% generate a structure for the RIGHT circle with the features of the circle as fields
  164. % ...color
  165. ObR.outer_circle.color = outer_circle_color;
  166. % ...diameter
  167. ObR.outer_circle.dimension = [0 0 dimensions_outer_circleR(2) dimensions_outer_circleR(2)];
  168. % center position on the screen;
  169. baseRect_outer = [ObR.outer_circle.dimension];
  170. % place in the first quarter
  171. ObR.outer_circle.dimension = CenterRectOnPoint(baseRect_outer, last_quarter, misure_schermo(4)/2);% da che cosa dipendono questi numeri???
  172. % same goes for the other circles
  173. ObR.inner_circle.color = inner_circle_color;
  174. ObR.inner_circle.dimension = [0 0 dimensions_inner_circleR(2) dimensions_inner_circleR(2)]
  175. baseRect_inner = [ObR.inner_circle.dimension];
  176. % place in the last quarter
  177. ObR.inner_circle.dimension = CenterRectOnPoint(baseRect_inner, last_quarter, misure_schermo(4)/2);
  178. ObR.middle_circle.color = middle_circle_color;
  179. ObR.middle_circle.dimension = [0 0 dimensions_middle_circleR(2) dimensions_middle_circleR(2)]
  180. baseRect_middle = [ObR.middle_circle.dimension];
  181. % place in the last quarter
  182. ObR.middle_circle.dimension = CenterRectOnPoint(baseRect_middle, last_quarter, misure_schermo(4)/2);
  183. %% we also have a black background. let's treat it as a structre as well.
  184. Bk.color = [0 0 0];
  185. Bk.dimension = misure_schermo;
  186. %% resolution setting:
  187. % every time participant presses, read values change. here we set the boundary values to which a variable circle will change its diameter based on the pressure produced
  188. % create a vector from 0 to diameter of outer circle in steps of
  189. % length(x)
  190. diameter_values_nonscaled_tmp = linspace(0, dimensions_outer_circleL(2), length(x));
  191. % in case participants press more than what they did in the max_force
  192. % evaluation, values bigger that outer_circle diameter are added, in order
  193. % not to get errors.
  194. % It should not happen though because it would mean the max_force
  195. % estimatimation was performed in a shitty way.
  196. diameter_values_nonscaled = [diameter_values_nonscaled_tmp ...
  197. diameter_values_nonscaled_tmp(end)+[1:100].*diff(diameter_values_nonscaled_tmp(1:2))];
  198. %% INSTRUCTIONS FOR the researcher
  199. Screen('FillRect', window, Bk.color, Bk.dimension);
  200. Screen('TextSize', window, 25);
  201. hor_alignement = round(misure_schermo(3)*0.5,0);
  202. ver_alignement = round(misure_schermo(4)*0.25,0);
  203. TMS_cond = contraction_task{1,1};
  204. DrawFormattedText(window,TMS_cond, hor_alignement,...
  205. ver_alignement, [1 1 1]);
  206. clear hor_alignement ver_alignement
  207. testo_sx = contraction_task{1,2};
  208. hor_alignement = round(misure_schermo(3)*0.25,0);
  209. ver_alignement = round(misure_schermo(4)*0.75,0);
  210. DrawFormattedText(window,testo_sx, hor_alignement,...
  211. ver_alignement, [1 1 1]);
  212. clear hor_alignement ver_alignement
  213. testo_dx = contraction_task{1,3};
  214. hor_alignement = round(misure_schermo(3)*0.75,0);
  215. ver_alignement = round(misure_schermo(4)*0.75,0);
  216. DrawFormattedText(window,testo_dx, hor_alignement,...
  217. ver_alignement, [1 1 1]);
  218. clear hor_alignement ver_alignement
  219. [VBL]=Screen(window, 'Flip', ifi, 1);
  220. % wait for keyboard press
  221. WaitSecs(2)
  222. %%
  223. while ~KbCheck
  224. end
  225. %% start noise
  226. [audiodata, infreq] = psychwavread('AirCool_Magstim_48000.wav');
  227. noise_seconds = 60*5;
  228. noise_short = audiodata(1:infreq*noise_seconds)';
  229. pasound2 = PsychPortAudio('Open', []);
  230. sound2 = [noise_short; noise_short];
  231. PsychPortAudio('Volume', pasound2, volume);
  232. PsychPortAudio('FillBuffer', pasound2, sound2);
  233. noise_ts = PsychPortAudio('Start',pasound2, 1, 1);
  234. %% RUN TIME ACTUAL EXPERIMENT
  235. Screen('FillRect', window, [0 0 0], misure_schermo);
  236. [VBL]=Screen(window, 'Flip', ifi, 1);
  237. tic
  238. on_spot = 0;
  239. for tr = 1:num_trials
  240. i = 0;
  241. while 1
  242. % read from serial port what arduino has written
  243. force_tmp = MoBi_scrittura(s);
  244. % split the 3 values that are read from the three pins in arduino
  245. force_tmp2 = (strsplit(force_tmp, '_'));
  246. % GET INFO ONLY FROM THE A0 PIN, which is the first read
  247. force_tmpL = str2double(force_tmp2{1});
  248. force_tmpR = str2double(force_tmp2{2});
  249. % force linearization.
  250. [linear_forceL idxL] = MoBi_linearize_force(force_tmpL, linearizeL, funzL);
  251. [linear_forceR idxR] = MoBi_linearize_force(force_tmpR, linearizeR, funzR);
  252. %%
  253. diameter_valuesL = diameter_values_nonscaled(idxL);
  254. diameter_valuesR = diameter_values_nonscaled(idxR);
  255. if on_spot == 0
  256. % draw left side circles in background
  257. ObL.variable_circle.color = variable_circle_colorL;
  258. ObL.variable_circle.dimension = [0 0 diameter_valuesL diameter_valuesL];
  259. baseRect_variable = [ObL.variable_circle.dimension];
  260. ObL.variable_circle.dimension = CenterRectOnPoint(baseRect_variable, first_quarter, misure_schermo(4)/2);
  261. Screen('FrameOval', window, ObL.outer_circle.color, ObL.outer_circle.dimension);
  262. Screen('FillOval', window, ObL.middle_circle.color, ObL.middle_circle.dimension);
  263. Screen('FillOval', window, ObL.inner_circle.color, ObL.inner_circle.dimension);
  264. Screen('FrameOval', window, ObL.variable_circle.color, ObL.variable_circle.dimension, variable_circle_thickness);
  265. % draw right side circles in background
  266. ObR.variable_circle.color = variable_circle_colorR;
  267. ObR.variable_circle.dimension = [0 0 diameter_valuesR diameter_valuesR];
  268. baseRect_variable = [ObR.variable_circle.dimension];
  269. ObR.variable_circle.dimension = CenterRectOnPoint(baseRect_variable, last_quarter, misure_schermo(4)/2);
  270. Screen('FrameOval', window, ObR.outer_circle.color, ObR.outer_circle.dimension);
  271. Screen('FillOval', window, ObR.middle_circle.color, ObR.middle_circle.dimension);
  272. Screen('FillOval', window, ObR.inner_circle.color, ObR.inner_circle.dimension);
  273. Screen('FrameOval', window, ObR.variable_circle.color, ObR.variable_circle.dimension, variable_circle_thickness);
  274. Screen('TextSize', window, 80);
  275. DrawFormattedText(window, '+', 'center','center', [1 1 1]);
  276. else
  277. Screen('FillRect', window, [0 0 0], misure_schermo);
  278. Screen('TextSize', window, 80);
  279. DrawFormattedText(window, '+', 'center','center', [1 1 1]);
  280. end
  281. % flip
  282. [VBL] = Screen(window, 'Flip', VBL+ifi_as);
  283. sprintf( '%f_%f_%f____%f_%f_%f', inner_force_limit_propL*max_force_left, linear_forceL, outer_force_limit_propL*max_force_left,...
  284. inner_force_limit_propR*max_force_right, linear_forceR, outer_force_limit_propR*max_force_right)
  285. %% check force range for TMS
  286. if (linear_forceL >= inner_force_limit_propL*max_force_left) && (linear_forceL <= outer_force_limit_propL*max_force_left)...
  287. && (linear_forceR >= inner_force_limit_propR*max_force_right) && (linear_forceR <= outer_force_limit_propR*max_force_right)
  288. i= i+1;
  289. on_spot = 1;
  290. Screen('FillRect', window, [0 0 0], misure_schermo);
  291. Screen('TextSize', window, 80);
  292. DrawFormattedText(window, '+', 'center','center', [1 1 1]);
  293. else % ... if force is out of range
  294. i = 0;
  295. on_spot = 0;
  296. % change colors of the circle that is out
  297. if (linear_forceL <= inner_force_limit_propL*max_force_left) || (linear_forceL >= outer_force_limit_propL*max_force_left)...
  298. variable_circle_colorL = [1 0 0];
  299. else
  300. variable_circle_colorL = [0 1 0];
  301. end
  302. if (linear_forceR <= inner_force_limit_propR*max_force_right) || (linear_forceR >= outer_force_limit_propR*max_force_right)
  303. variable_circle_colorR = [1 0 0];
  304. else
  305. variable_circle_colorR = [0 1 0];
  306. end
  307. end
  308. % in case i is equal or greater than than the frames to be waited
  309. % for TMS to be delivered, then deliver TMS
  310. if i >= TMS_int_nf(tr)
  311. can_i_trigger = 1;
  312. % function implementing also trigger value
  313. MoBi_Trigger(ioObj,address,TMS_trigger, can_i_trigger);
  314. can_i_trigger = 0;
  315. TR.TMS_timing(tr) = VBL;
  316. TR.i(tr) = i;
  317. TR.ns(tr) = TMS_int_ns(tr);
  318. TR.nf(tr) = TMS_int_nf(tr);
  319. TR.tictoc(tr) = toc;
  320. disp(strcat('TMS', '_', num2str(tr)))
  321. WaitSecs(delay_after_TMS)
  322. % break the while loop and start another trial
  323. break
  324. end
  325. end
  326. end
  327. sca
  328. % forces = struct;
  329. % forces.max_force_left = max_force_left;
  330. % forces.max_force_right = max_force_right;
  331. % forces.sbj = sbj;
  332. % forces.order = ordine
  333. % forces.block = block;
  334. % forces.within_ordine = row_tabella;
  335. % forces.session = blocco;
  336. PsychPortAudio('Stop', pasound2,0);
  337. PsychPortAudio('Close');
  338. clear audiodata sound2 noise_short pasound2 sound2
  339. save(data_subject)
  340. end