00001 /*!@file AppPsycho/psycho-spatial-nback.C Psychophysics test to measure the effect of executive tasks on spatial memory */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/AppPsycho/psycho-spatial-orientation-2back.C $ 00035 // $Id: psycho-spatial-memory.C 13040 2010-03-23 03:59:25Z nnoori $ 00036 // 00037 00038 #include "Component/ModelManager.H" 00039 #include "Image/Image.H" 00040 #include "Psycho/PsychoDisplay.H" 00041 #include "Psycho/EyeTrackerConfigurator.H" 00042 #include "Psycho/EyeTracker.H" 00043 #include "Psycho/PsychoOpts.H" 00044 #include "Component/EventLog.H" 00045 #include "Component/ComponentOpts.H" 00046 #include "Raster/Raster.H" 00047 #include "Util/MathFunctions.H" 00048 #include "Util/Types.H" 00049 #include "GameBoard/basic-graphics.H" 00050 #include <sys/types.h> 00051 #include <dirent.h> 00052 #include <errno.h> 00053 #include <vector> 00054 #include <string> 00055 #include <iostream> 00056 #include <SDL/SDL.h> 00057 #include <SDL/SDL_image.h> 00058 #include <SDL/SDL_mixer.h> 00059 #include <stdio.h> 00060 #include <stdlib.h> 00061 #include <sstream> 00062 #include <time.h> 00063 #include "Image/DrawOps.H" 00064 #include "GameBoard/resize.h" 00065 #include <iostream> 00066 #include <fstream> 00067 #include <set> 00068 #include <algorithm> 00069 #include <ctime> 00070 00071 #ifndef INVT_HAVE_LIBSDL_IMAGE 00072 #include <cstdio> 00073 int main() 00074 { 00075 fprintf(stderr, "The SDL_image library must be installed to use this program\n"); 00076 return 1; 00077 } 00078 00079 #else 00080 00081 00082 00083 using namespace std; 00084 00085 // ###################################################################### 00086 00087 ModelManager manager("Psycho-Spatial-nback"); 00088 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00089 map<uint,uint> testMap ; 00090 map<string,string> argMap ; 00091 map<string,vector<SDL_Rect*>*> clipsmap; 00092 00093 00094 ////////////////////////////////////////////// 00095 // a functionf for stringigying things 00096 ////////////////////////////////////////////// 00097 template <class T> std::string stringify(T i) 00098 { 00099 ostringstream o ; 00100 o << i ; 00101 return o.str(); 00102 } 00103 00104 00105 int pickOne(int l){ 00106 int s = (l*l+l)/2; 00107 int pre_p = rand()%s +1; 00108 int p = 1; 00109 int ps = 0 ; 00110 for(int i=1;i<=l;i++){ 00111 ps +=i; 00112 if(pre_p > ps) p=i+1; 00113 } 00114 return p-1; 00115 } 00116 00117 00118 double getAvarage(vector<long> v){ 00119 double f = 0.0 ; 00120 for( uint i = 0 ; i < v.size() ; i++ ){ 00121 f += v[i] ; 00122 } 00123 if (v.size()!=0) return f/v.size() ; 00124 return -1 ; 00125 } 00126 00127 double getVariance(vector<long> v){ 00128 double m = getAvarage(v); 00129 double var = 0.0 ; 00130 for( uint i = 0 ; i < v.size(); i++ ){ 00131 var += (v[i]-m)*(v[i]-m) ; 00132 } 00133 if (v.size()!=0) return var/v.size() ; 00134 return -1 ; 00135 } 00136 00137 bool itIsInThere(int x , vector<int> bag){ 00138 for( uint i=0 ; i < bag.size(); i++ ){ 00139 if(x == bag[i]) return true ; 00140 } 00141 return false ; 00142 } 00143 00144 00145 //////////////////////////////////////////////////////////////////// 00146 //// gets a string as the argument and returns a string composed of 00147 //// characters of the first string sorted in the ascending order 00148 /////////////////////////////////////////////////////////////////// 00149 string ascSort(string st) 00150 { 00151 string res = "" ; 00152 vector<string> v = vector<string>(); 00153 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00154 00155 std::sort(v.begin(), v.end()); 00156 00157 for ( uint i = 0 ; i < v.size() ; i++ ){ 00158 res += v[i] ; 00159 } 00160 return res; 00161 } 00162 00163 00164 00165 //////////////////////////////////////////////////////////////////// 00166 //// gets a string as the argument and returns a string composed of 00167 //// characters of the first string sorted in the descending order 00168 /////////////////////////////////////////////////////////////////// 00169 string desSort(string st) 00170 { 00171 string res = "" ; 00172 vector<string> v = vector<string>(); 00173 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00174 std::sort(v.begin(), v.end()); 00175 std::reverse(v.begin(), v.end()); 00176 for ( uint i = 0 ; i < v.size() ; i++ ){ 00177 res += v[i] ; 00178 } 00179 return res; 00180 } 00181 00182 00183 //////////////////////////////////////////////////////// 00184 ///// simply generates a sequence of characters out of master string 00185 //////////////////////////////////////////////////////// 00186 00187 string getARandomString(uint l, string alphabet="0123456789" ){ 00188 00189 string test = string("") ; 00190 string retString ; 00191 test = "" ; 00192 string tp = string("") ; 00193 vector<int> pickedones = vector<int>() ; 00194 for(uint i = 0 ; i < l ; i++){ 00195 int nd; 00196 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones)) ; 00197 pickedones.push_back(nd); 00198 tp = alphabet.substr(nd,1) ; 00199 test += tp ; 00200 } 00201 retString = test ; 00202 return retString ; 00203 } 00204 00205 00206 00207 /////////////////////////////////////////////////////// 00208 //this function is not called in this program, but it generates a random string and it will show it in 00209 //a random place on the screen. 00210 ////////////////////////////////////////////////////// 00211 string digitMemorizationTask(uint l, string alphabet="0123456789" , int displayFrame = 10 ){ 00212 d->clearScreen() ; 00213 vector<int> pickedones = vector<int>() ; 00214 string test = string("") ; 00215 string tp = string("") ; 00216 for(uint i = 0 ; i < l ; i++){ 00217 int nd; 00218 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones) && pickedones.size() <= alphabet.size()) ; 00219 pickedones.push_back(nd); 00220 tp = alphabet.substr(nd,1) ; 00221 test += tp ; 00222 } 00223 d->displayText(test,true,0) ; 00224 d->waitFrames(displayFrame) ; 00225 d->clearScreen() ; 00226 return test ; 00227 } 00228 00229 00230 //////////////////////////////////////////////////////// 00231 ///////this will change the order of elements in a vector to a random order 00232 //////////////////////////////////////////////////////// 00233 void scramble(vector<string>& v){ 00234 vector<string> tv = vector<string>() ; 00235 while(v.size()>0){ 00236 tv.push_back(v[0]); 00237 v.erase(v.begin()); 00238 } 00239 int i = 0 ; 00240 while(tv.size()>0){ 00241 i = rand()%tv.size() ; 00242 v.push_back(tv[i]); 00243 tv.erase(tv.begin()+i); 00244 } 00245 } 00246 00247 void scramble(vector<int>& v){ 00248 vector<int> tv = vector<int>() ; 00249 while(v.size()>0){ 00250 tv.push_back(v[0]); 00251 v.erase(v.begin()); 00252 } 00253 int i = 0 ; 00254 while(tv.size()>0){ 00255 i = rand()%tv.size() ; 00256 v.push_back(tv[i]); 00257 tv.erase(tv.begin()+i); 00258 } 00259 } 00260 00261 //////////////////////////////////////////////////////////////// 00262 ////This is our button factory 00263 //////////////////////////////////////////////////////////////// 00264 SDL_Surface* getButtonImage(string label , PixRGB<byte> txtcolor=PixRGB<byte>(0,0,0) , PixRGB<byte> bgcolor=PixRGB<byte>(255,255,255) ,Point2D<int> size = Point2D<int>(100,100) ,PixRGB<byte> bordercolor=PixRGB<byte>(0,0,0) , int border=3){ 00265 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00266 textIm.clear(bgcolor); 00267 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor); 00268 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00269 Uint32 bc = d->getUint32color(bordercolor); 00270 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border); 00271 SDL_Surface* blank =getABlankSurface(size.i , size.j); 00272 SDL_Rect clip; 00273 clip.x = 0 ; 00274 clip.y = 0 ; 00275 clip.w = size.i ; 00276 clip.h = size.j ; 00277 apply_surface(0,0,*surf,*blank,clip); 00278 dumpSurface(surf) ; 00279 return blank ; 00280 } 00281 00282 //////////////////////////////////////////////////////////////////////// 00283 ////This is the function for creating the keypad, in fact it generates 00284 ////12 buttons and associates the actions to the region for each button 00285 //////////////////////////////////////////////////////////////////////// 00286 00287 SDL_Surface* getKeyPad(string alphabet,map<string , SDL_Rect>& buttmap){ 00288 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3); 00289 SDL_Rect clip; 00290 clip.x=0; 00291 clip.y=0; 00292 int numofrows = alphabet.size()/3 +1; 00293 if(alphabet.size()%3 != 0 ) numofrows++ ; 00294 int numofcolumns = 3 ; 00295 clip.w= pad->w / numofcolumns ; 00296 clip.h = pad->h / numofrows ; 00297 00298 //keys for 1 to 9 00299 for( int i = 0 ; i < numofrows*3 ; i++){ 00300 SDL_Surface* but ; 00301 if((uint)i < alphabet.size()){ 00302 but = getButtonImage(alphabet.substr(i,1),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00303 }else{ 00304 but = getButtonImage(" ",PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00305 } 00306 00307 SDL_Rect cl ; 00308 cl.x = ((i)%numofcolumns)*(pad->w)/numofcolumns ; cl.y= ((i)/numofcolumns)*((pad->h)/numofrows) ; 00309 cl.w = clip.w ; 00310 cl.h = clip.h ; 00311 apply_surface( cl.x , cl.y ,*but,*pad,clip); 00312 if((uint)i < alphabet.size()) buttmap[alphabet.substr(i,1)] = cl ; 00313 dumpSurface(but); 00314 } 00315 SDL_Rect cl1 ; 00316 cl1.x = 0 ; cl1.y= (numofrows-1)*((pad->h)/numofrows) ; 00317 cl1.w = clip.w ; 00318 cl1.h = clip.h ; 00319 buttmap["!"] = cl1 ; 00320 SDL_Surface* but = getButtonImage(string("<-"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00321 apply_surface(0, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00322 dumpSurface(but); 00323 SDL_Rect cl2 ; 00324 cl2.x = (pad->w)/numofcolumns ; cl2.y= (numofrows-1)*((pad->h)/numofrows) ; 00325 cl2.w = clip.w ; 00326 cl2.h = clip.h ; 00327 buttmap[" "] = cl2 ; 00328 but = getButtonImage(string("spc"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00329 apply_surface((pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00330 dumpSurface(but); 00331 SDL_Rect cl3 ; 00332 cl3.x = 2*(pad->w)/numofcolumns ; cl3.y= (numofrows-1)*((pad->h)/numofrows) ; 00333 cl3.w = clip.w ; 00334 cl3.h = clip.h ; 00335 buttmap["*"] = cl3 ; 00336 but = getButtonImage(string("Ok"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / numofcolumns , pad->h / numofrows),PixRGB<byte>(255, 98 , 25),3); 00337 apply_surface(2*(pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00338 dumpSurface(but); 00339 return pad ; 00340 } 00341 00342 00343 00344 00345 /////////////////////////////////////////////////////////////////////////// 00346 /////this function listens to mouse clicks and then finds the region of the screen 00347 /////associated with the action, buttmap is the map of the region, offset is the offset of 00348 /////buttons 00349 /////////////////////////////////////////////////////////////////////////// 00350 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){ 00351 int quit = 0 ; 00352 string s ; 00353 SDL_Event event ; 00354 while( quit!=2 ){ 00355 while( SDL_PollEvent( &event ) ) { 00356 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){ 00357 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){ 00358 if(event.button.x >= (it->second).x + offset.i && event.button.x <= (it->second).x + (it->second).w + offset.i && event.button.y >= (it->second).y+ offset.j && event.button.y <= (it->second).y + (it->second).h + offset.j) { 00359 quit = 2 ; 00360 s = it->first ; 00361 break; 00362 } 00363 00364 } 00365 } 00366 00367 } 00368 } 00369 return s ; 00370 00371 } 00372 00373 00374 //////////////////////////////////////////////////// 00375 ////This function creates a virtual keypad, creates a map of buttons 00376 ////and their representation area and listens to the button press and at 00377 ////the end returns the keyed digits 00378 //////////////////////////////////////////////////// 00379 string getDigitSequenceFromSubject(string alphabet="0123456789" , uint maxl = 7 , string message=""){ 00380 d->showCursor(true) ; 00381 //let's creat a map to map actions to regions of the screen, each region is represented as an SDL_Rect 00382 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>(); 00383 //now let's get the keypad surface while we get the actions map to regions 00384 SDL_Surface * keypad = getKeyPad(alphabet,*buttmap); 00385 //this will be the offset of displaying the keypad on the screen 00386 SDL_Rect offset ; 00387 offset.x = (d->getWidth() - keypad->w) /2; 00388 offset.y = (d-> getHeight() - keypad->h) /2; 00389 //d->displayText(message, Point2D<int>(d->getWidth()/3,d->getHeight()*2 /16) , PixRGB<byte>(0,0,0) ,PixRGB<byte>(127,127,127)) ; 00390 SDL_Surface* msgp = getButtonImage(message ,PixRGB<byte>(195,60,12) ,PixRGB<byte>(127,127,127) ,Point2D<int>(d->getWidth()/6,d->getHeight() /15) ,PixRGB<byte>(127,127,127) , 4) ; 00391 SDL_Rect msgoffs ; msgoffs.x = (d->getWidth() - msgp->w) /2 ; msgoffs.y = 2*d->getHeight()/9 ; 00392 d->displaySDLSurfacePatch(msgp , &msgoffs , NULL , -2 , false ,true ) ; 00393 dumpSurface(msgp) ; 00394 //now let's display the keypad 00395 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true); 00396 //this will hold the final string keyed be the subject 00397 string p = string("") ; 00398 //this is a temporary string holding the last action related to the pressed key 00399 string tp = string(""); 00400 //now let's record subject's key press 00401 while( tp.compare("*")!=0 ){ 00402 //this button is actually the display for the current string 00403 SDL_Surface* dp = getButtonImage(p ,PixRGB<byte>(195,60,12) ,PixRGB<byte>(255,255,255) ,Point2D<int>(d->getWidth()/6,d->getHeight() /15) ,PixRGB<byte>(0,25,180) , 4) ; 00404 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ; 00405 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ; 00406 //now let's listen to button events 00407 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ; 00408 dumpSurface(dp) ; 00409 if(tp.compare("!")==0 && p.size()>=0 ) { 00410 if (p.size()>0) p = p.substr(0,p.size()-1) ; 00411 }else{ 00412 if(p.size() < maxl && tp.compare("*")!=0) { 00413 p +=tp ; 00414 } 00415 00416 } 00417 00418 } 00419 00420 buttmap = 0 ; 00421 dumpSurface(keypad) ; 00422 d->clearScreen() ; 00423 return p ; 00424 00425 } 00426 00427 00428 00429 /////////////////////////////////////////////////////////////// 00430 //////gets the test string, answer and the mode and identifies if 00431 //////the answer matches the thing it should be, mode=0 checks if 00432 //////if the answer and test string simply the same, mode=1 matches 00433 //////the answer against the ascending sorted string of the test string 00434 //////mode=2 compares the answer against the descending sorted of 00435 //////the test string 00436 /////////////////////////////////////////////////////////////// 00437 bool isAnswerCorrect(string test , string answer , int mode){ 00438 00439 if(mode == 0 && answer.compare(test)==0) return true ; 00440 00441 if(mode == 1 && answer.compare(ascSort(test))==0) return true ; 00442 00443 if(mode == 2 && answer.compare(desSort(test))==0) return true ; 00444 00445 return false; 00446 } 00447 00448 00449 00450 int addArgument(const string st,const string delim="="){ 00451 int i = st.find(delim) ; 00452 argMap[st.substr(0,i)] = st.substr(i+1); 00453 00454 return 0 ; 00455 } 00456 00457 std::string getArgumentValue(string arg){ 00458 return argMap[arg] ; 00459 } 00460 00461 00462 vector<int> spatial_memory_task(int onsetTime, int isd ,int rad=100 , int ma=45 ,int Ma=90){ 00463 00464 int w = d->getWidth(); 00465 int h = d->getHeight(); 00466 int a1 = rand() % 360 ; 00467 int direction = (int)(((rand()%2)-0.5)/0.5); 00468 int a2 =a1 +direction*((rand() % (Ma-ma))+ma); 00469 //d->displayFixation(); 00470 d->displayRedDotFixation(w/2+rad*cos(a1*3.1415/180),h/2 + rad*sin(a1*3.1415/180)); 00471 d->waitFrames(onsetTime); 00472 d->clearScreen(); 00473 //d->displayFixation(); 00474 d->waitFrames(isd); 00475 d->displayRedDotFixation(w/2+rad*cos(a2*3.1415/180),h/2 + rad*sin(a2*3.1415/180)); 00476 d->waitFrames(onsetTime); 00477 d->clearScreen(); 00478 vector<int> angles; 00479 angles.push_back(a1); 00480 angles.push_back(a2); 00481 return angles ; 00482 } 00483 00484 vector<int> getA2NonRepeatingSeqence(int numOfElements , int lenght){ 00485 vector<int> sequence; 00486 //let's first push two elements in the sequence 00487 sequence.push_back(rand()%numOfElements); 00488 sequence.push_back(rand()%numOfElements); 00489 for(int i = 2 ; i < lenght ; i++){ 00490 int r = rand()%(numOfElements) ; 00491 if(r== sequence[i-2]) r = (r+1)%numOfElements; 00492 sequence.push_back(r); 00493 } 00494 00495 return sequence; 00496 } 00497 00498 vector<int> getA2RepeatingSequence(int numOfElements , int length){ 00499 vector<int> nonrepeatingsequence = getA2NonRepeatingSeqence(numOfElements,length); 00500 int repeatPlace = 2+ pickOne(length-2); 00501 nonrepeatingsequence[repeatPlace] = nonrepeatingsequence[repeatPlace-2]; 00502 return nonrepeatingsequence; 00503 } 00504 00505 00506 00507 vector<int> getA1NonRepeatingSeqence(int numOfElements , int lenght){ 00508 vector<int> sequence; 00509 //let's first push one elements in the sequence 00510 sequence.push_back(rand()%numOfElements); 00511 // sequence.push_back(rand()%numOfElements); 00512 for(int i = 1 ; i < lenght ; i++){ 00513 int r = rand()%(numOfElements) ; 00514 if(r== sequence[i-1]) r = (r+1)%numOfElements; 00515 sequence.push_back(r); 00516 } 00517 00518 return sequence; 00519 } 00520 00521 vector<int> getA1RepeatingSequence(int numOfElements , int length){ 00522 vector<int> nonrepeatingsequence = getA1NonRepeatingSeqence(numOfElements,length); 00523 int repeatPlace = 1+ pickOne(length-1); 00524 nonrepeatingsequence[repeatPlace] = nonrepeatingsequence[repeatPlace-1]; 00525 return nonrepeatingsequence; 00526 } 00527 00528 00529 vector<int> getNonRepeatingSeqenceForPassiveTest(int numOfElements , int lenght){ 00530 vector<int> sequence; 00531 //let's first push two elements in the sequence 00532 for(int i = 0 ; i < lenght ; i++){ 00533 int r = rand()%(numOfElements-1) +1 ; 00534 sequence.push_back(r); 00535 } 00536 return sequence; 00537 } 00538 00539 vector<int> getRepeatingSeqenceForPassiveTest(int numOfElements , int lenght){ 00540 vector<int> sequence = getNonRepeatingSeqenceForPassiveTest(numOfElements,lenght); 00541 int p = pickOne(lenght); 00542 sequence[p] = 0 ; 00543 return sequence; 00544 } 00545 /* 00546 int spatial_memory_retrival(vector<int> dotsVector,int dir ,int ma=30 , int Ma=120 ,int ds=30 ){ 00547 00548 int w = d->getWidth(); 00549 int h = d->getHeight(); 00550 int change = rand()%2; 00551 int neg = dotsVector.at(0); int pos = dotsVector.at(1); 00552 switch( change ){ 00553 case 0 : d->pushEvent("same target");break; 00554 case 1 : d->pushEvent("target changed");break; 00555 } 00556 if(change == 1){ 00557 int chDir = rand()%2; 00558 int c=0; 00559 if(chDir==0){ 00560 c =((rand()%2 -0.5)/0.5 ); 00561 if( neg+ ds > Ma ) c = -1 ; 00562 if(neg -ds < ma ) c=+1 ; 00563 neg = neg + c*ds ; 00564 } 00565 if(chDir==1){ 00566 c =((rand()%2 -0.5)/0.5 ); 00567 if( pos+ ds > Ma ) c = -1 ; 00568 if(pos -ds < ma ) c=+1 ; 00569 pos = pos + c*ds ; 00570 } 00571 } 00572 00573 d->pushEvent("for retrieval dots showed at negative side :"+ stringify(neg)+" positive side:" + stringify(pos)); 00574 if(dir == 0){ 00575 d->displayRedDotFixation(w/2+pos,h/2); 00576 d->displayRedDotFixation(w/2-neg,h/2); 00577 } 00578 if(dir == 1){ 00579 d->displayRedDotFixation(w/2,h/2+pos); 00580 d->displayRedDotFixation(w/2,h/2-neg); 00581 } 00582 d->waitFrames(30); 00583 d->clearScreen(); 00584 string ans = getDigitSequenceFromSubject("yn-",1,"same dots?"); 00585 int res = 0 ; 00586 if(change==0 && ans.compare("y")==0) res=1; 00587 if(change==1 && ans.compare("n")==0) res=1; 00588 return res ; 00589 } 00590 */ 00591 int playTone(Mix_Music* tone ){ 00592 if(Mix_PlayMusic(tone,0)==-1){return -1;} 00593 while(Mix_PlayingMusic()==1){} ; 00594 return 0 ; 00595 } 00596 00597 00598 00599 00600 int spatial_memory_retrival(vector<int> angles ,int rad = 100 ){ 00601 int res=0 ; 00602 int flip = rand()%2; 00603 int w = d->getWidth(); 00604 int h = d->getHeight(); 00605 if(flip==0){ 00606 d->displayRedDotFixation(w/2+rad*cos(angles.at(0)*3.1415/180),h/2 + rad*sin(angles.at(0)*3.1415/180)); 00607 d->displayRedDotFixation(w/2+rad*cos(angles.at(1)*3.1415/180),h/2 + rad*sin(angles.at(1)*3.1415/180)); 00608 }else{ 00609 int a1=angles.at(0) % 360; 00610 int a2=angles.at(1) % 360; 00611 if (a2<a1) { 00612 int tmp = a2 ; 00613 a2=a1; 00614 a1=tmp; 00615 } 00616 int sflip=rand()%2; 00617 int del = ((rand()%15) + 30); 00618 if(sflip==0){ 00619 a1=a1-del; 00620 }else{ 00621 a2=a2+del; 00622 } 00623 d->displayRedDotFixation(w/2+rad*cos(a1*3.1415/180),h/2 + rad*sin(a1*3.1415/180)); 00624 d->displayRedDotFixation(w/2+rad*cos(a2*3.1415/180),h/2 + rad*sin(a2*3.1415/180)); 00625 } 00626 d->waitFrames(20); 00627 d->clearScreen(); 00628 string ans = getDigitSequenceFromSubject("yn",1,"same dots?"); 00629 if(flip==0){ 00630 res = 0 ; 00631 if(ans.compare("y")==0) res=1; 00632 }else{ 00633 res = 0 ; 00634 if(ans.compare("n")==0) res=1; 00635 } 00636 return res ; 00637 } 00638 00639 std::string getUsageComment(){ 00640 00641 string com = string("\nlist of arguments : \n"); 00642 00643 com += "\nlogfile=[logfilename.psy] {default = psycho-sm-or.psy}\n" ; 00644 com += "\nmemo=[a_string_without_white_space]\n"; 00645 com += "\nstring-size=[>0](the size of counter string){default=4} \n"; 00646 com += "\nsubject=[subject_name] \n" ; 00647 com += "\nnum-of-trials=[>1] (number of trials ) {default=10}\n"; 00648 com += "\nalphabet=[a string of characters](a string of characters){default=abcdefghijklmnopqrstuvwxyz}\n"; 00649 com += "\nmode=[1,2,3](1 for spatial memory task 2 for single counter task, 2 for concurrent task){default=1}\n"; 00650 com += "\nsingle-dot-onset=[>1](number of frames that the single dot should be presented){default=16}\n"; 00651 com += "\ndots_ISI=[>1](number of frames between dots presentations){default=16}\n"; 00652 com += "\ndots-radius=[>1](the radius for circle of dots in pixel){default=100}\n"; 00653 com += "\ndots-min-radius=[>0](minimum distance of dots from center){default=32}\n"; 00654 com += "\ndots-max-radius=[>0] (maximum distance of dots from center){default=158}\n"; 00655 com += "\nspatial-delay=[>0](number of frames for spatial memory task ){default=180}\n"; 00656 com += "\n spatial-counter-ISI=[>1](numer of frames between last dot presentation and start of counter task){default=16}\n"; 00657 com += "\n counter-length=[>1](total lenght of counter experiment in frames){default=300}\n"; 00658 com += "\n counter-spatial-query-ISI=[>1](the delay between end of counter trail and start of spatial memory query in number of frames){default=16}\n"; 00659 com += "\n spatial-query-length=[>1](the total length for showing the spatial memory test in number of frames){default=60}\n"; 00660 com += "\n spatial-query-counter-query-ISI=[>1](number of frames between the unspeeded spatial memory query and showing the counter query){default=30}\n"; 00661 com += "\n counter-query-length=[>1](number of frames for presenting the counter query){default=60}\n"; 00662 com += "\n cue-onset-frames=[>1](){default=3}\n";; 00663 com += "\nsound-dir=[path to wav files directory]{default=..}\n"; 00664 com += "\ntone1=[a valid file name](name of wav file without extension for tone 1){default=sin}\n"; 00665 com += "\ntone2=[a valid file name](name of wav file without extension for tone 2){default=square}\n"; 00666 com += "\ndot-shift=[>1](amount of shift in dots position in pixel)[default=16]\n"; 00667 com +="\n2back-isi=[>1](inter stimuli interval between two items of 2 back test){default=30}\n"; 00668 return com ; 00669 } 00670 00671 extern "C" int main(const int argc, char** argv) 00672 { 00673 00674 MYLOGVERB = LOG_INFO; // suppress debug messages 00675 //let's push the initial value for the parameters 00676 argMap["experiment"]="spatial-memory-test"; 00677 argMap["logfile"]="psycho-sm.psy" ; 00678 argMap["string-size"]="5" ; 00679 argMap["num-of-trials"]="2"; 00680 argMap["subject"]="" ; 00681 argMap["memo"]="" ; 00682 argMap["single-dot-onset"]="16" ; 00683 argMap["dots-ISI"]="16"; 00684 argMap["dots_radius"]="100"; 00685 argMap["spatial-delay"]="180"; 00686 argMap["spatial-counter-ISI"]="16"; 00687 argMap["counter-length"]="300"; 00688 argMap["counter-spatial-query-ISI"]="16"; 00689 argMap["spatial-query-length"]="60"; 00690 argMap["spatial-query-counter-query-ISI"]="30"; 00691 argMap["counter-query-length"]="60"; 00692 argMap["alphabet"]="djs"; 00693 argMap["mode"]="0" ; 00694 argMap["cue-onset-frames"] = "3" ; 00695 argMap["sound-dir"]=".."; 00696 argMap["tone1"]="sine"; 00697 argMap["tone2"]="square"; 00698 argMap["cue-file"]="cue1"; 00699 argMap["min-tone-wait"]="50"; 00700 argMap["max-tone-wait"]="80"; 00701 argMap["dots_min_angle"]="45"; 00702 argMap["dots_max_angle"]="90"; 00703 argMap["dot-shift"] = "32"; 00704 argMap["backtask-length"]="7"; 00705 argMap["2back-isi"]="30"; 00706 manager.addSubComponent(d); 00707 nub::soft_ref<EventLog> el(new EventLog(manager)); 00708 manager.addSubComponent(el); 00709 d->setEventLog(el); 00710 00711 00712 if (manager.parseCommandLine(argc, argv, 00713 "at least one argument needed", 1, -1)==false){ 00714 cout<<getUsageComment()<<endl; 00715 return(1); 00716 } 00717 00718 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00719 addArgument(manager.getExtraArg(i),std::string("=")) ; 00720 } 00721 00722 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00723 00724 // let's get all our ModelComponent instances started: 00725 manager.start(); 00726 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00727 // let's display an ISCAN calibration grid: 00728 d->clearScreen(); 00729 d->displayISCANcalib(); 00730 d->waitForMouseClick(); 00731 d->displayText("Here the experiment starts! click to start!"); 00732 d->waitForMouseClick(); 00733 d->clearScreen(); 00734 //let's see in what mode the user like to run the program 00735 //int mode = atoi(argMap["mode"].c_str()); 00736 string masterString=argMap["alphabet"]; 00737 00738 int mode = atoi(argMap["mode"].c_str()); 00739 int numOfTests = atoi(argMap["num-of-trials"].c_str()) ; 00740 00741 int dots_ISI = atoi(argMap["dots-ISI"].c_str()) ; 00742 int dot_onset = atoi(argMap["single-dot-onset"].c_str()); 00743 int dots_radius = atoi(argMap["dots_radius"].c_str()); 00744 int dots_min_angle = atoi(argMap["dots_min_angle"].c_str()); 00745 int dots_max_angle = atoi(argMap["dots_max_angle"].c_str()); 00746 // int delayForSorting = atoi(argMap["sorting-delay"].c_str()); 00747 int numOfBackTaskElements = masterString.size(); 00748 int lengthOfBackTask = atoi(argMap["backtask-length"].c_str()); 00749 // int dot_max_change = atoi(argMap["dot-shift"].c_str()); 00750 int two_back_isi = atoi(argMap["2back-isi"].c_str()); 00751 vector<int> orientation_task_Vector; 00752 for( int i = 0 ; i< numOfTests ; i++ ){ 00753 orientation_task_Vector.push_back(0); 00754 orientation_task_Vector.push_back(1); 00755 } 00756 00757 scramble(orientation_task_Vector); 00758 //let's do calibration 00759 00760 00761 d->clearScreen(); 00762 00763 cout<< stringify(d->getWidth())<<" x "<<stringify(d->getHeight())<<endl; 00764 // Mix_Music* cueMusic = NULL;//this is the cue for the start of trial 00765 Mix_Music* tone1 = NULL;//tone 1 00766 Mix_Music* tone2 = NULL;//tone 2 00767 map<int,Mix_Music*> audio_map ;//we will have access to the audios for stimulus presentation using this map 00768 map<string,int> charmap ; 00769 map<int,string> charinvmap ; 00770 //now let's open the audio channel 00771 if( Mix_OpenAudio( 22050, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 ){ 00772 LINFO( "did not open the mix-audio") ; 00773 return -1 ; 00774 } 00775 //now that everyting is ok, let's load the main string audio files and push them in a map 00776 for(uint i = 0; i < masterString.size() ; i++){ 00777 string str = argMap["sound-dir"]+"/"+masterString.substr(i,1)+".wav"; 00778 audio_map[i]=Mix_LoadMUS(str.c_str()); 00779 charmap[masterString.substr(i,1)]=i; 00780 charinvmap[i]=masterString.substr(i,1) ; 00781 } 00782 00783 for( uint i=10;i<100 ;i++ ){ 00784 charmap[stringify(i)]=i; 00785 charinvmap[i]=stringify(i); 00786 } 00787 00788 00789 string tmpstr = argMap["sound-dir"]+"/"+argMap["tone1"]+".wav"; 00790 tone1 = Mix_LoadMUS(tmpstr.c_str()); 00791 tmpstr = argMap["sound-dir"]+"/"+argMap["tone2"]+".wav"; 00792 tone2 = Mix_LoadMUS(tmpstr.c_str()); 00793 00794 int cr = numOfTests ;//this is the counter for number of rounds 00795 d->showCursor(true); 00796 d->displayText("click one of the mouse buttons to start!"); 00797 d->waitForMouseClick() ; 00798 d->showCursor(false); 00799 00800 map<int,int> correctSPMMap;correctSPMMap[0]=0;correctSPMMap[1]=0;correctSPMMap[2]=0;correctSPMMap[3]=0; 00801 map<int,int> incorrectSPMMap;incorrectSPMMap[0]=0;incorrectSPMMap[1]=0;incorrectSPMMap[2]=0;incorrectSPMMap[3]=0; 00802 cr=0; 00803 while( cr < 2*numOfTests ){ 00804 d->pushEvent("**************************************") ; 00805 int flp = rand()%2; 00806 //twoBackTaskType = 0 is reserved for non-repeating 2back task twoBackTaskType = 1 is for repeating one 00807 int twoBackTaskType = 0 ; 00808 if(flp == 0) twoBackTaskType = 1; 00809 00810 switch(twoBackTaskType){ 00811 case 0 : d->pushEvent("non-repeating string");break; 00812 case 1 : d->pushEvent("repeating string");break; 00813 } 00814 00815 vector<int> backTaskSequence; 00816 if(mode == 2){ 00817 switch(twoBackTaskType){ 00818 case 0 : backTaskSequence = getA2NonRepeatingSeqence(numOfBackTaskElements,lengthOfBackTask);break; 00819 case 1 : backTaskSequence = getA2RepeatingSequence(numOfBackTaskElements,lengthOfBackTask);break; 00820 } 00821 } 00822 if(mode==0){ 00823 switch(twoBackTaskType){ 00824 case 0 : backTaskSequence = getNonRepeatingSeqenceForPassiveTest(numOfBackTaskElements,lengthOfBackTask);break; 00825 case 1 : backTaskSequence = getRepeatingSeqenceForPassiveTest(numOfBackTaskElements,lengthOfBackTask);break; 00826 } 00827 } 00828 if(mode==1){ 00829 switch(twoBackTaskType){ 00830 case 0 : backTaskSequence = getA1NonRepeatingSeqence(numOfBackTaskElements,lengthOfBackTask);break; 00831 case 1 : backTaskSequence = getA1RepeatingSequence(numOfBackTaskElements,lengthOfBackTask);break; 00832 } 00833 } 00834 00835 d->showCursor(false); 00836 d->clearScreen() ; 00837 d->clearScreen() ; 00838 d->displayFixationBlink(); 00839 00840 d->pushEvent("trial number: "+ stringify(cr)); 00841 d->pushEvent("verbal task type : " + stringify(twoBackTaskType)); 00842 string seq = ""; 00843 for( int i = 0 ; i < lengthOfBackTask ; i++ ){ 00844 seq += stringify(backTaskSequence[i]) ; 00845 } 00846 d->pushEvent("verbal task sequence: "+seq); 00847 d->waitFrames(30); 00848 d->displayFixation(); 00849 d->waitFrames(10); 00850 d->clearScreen() ; 00851 playTone(tone1); 00852 vector<int> angles = spatial_memory_task(dot_onset,dots_ISI,dots_radius,dots_min_angle,dots_max_angle); 00853 d->pushEvent("dots showed at these angles :"+ stringify(angles.at(0))+" and " + stringify(angles.at(1))); 00854 00855 d->displayFixation(); 00856 d->waitFrames(15); 00857 00858 //let's play the items of 2backtask 00859 for( int i = 0 ; i < lengthOfBackTask ; i++ ){ 00860 playTone(audio_map[backTaskSequence[i]]); 00861 d->waitFrames(two_back_isi); 00862 } 00863 int currentTask=mode; 00864 00865 if(currentTask==0){ 00866 d->pushEvent("task condition: engage"); 00867 00868 }else{ 00869 d->pushEvent("task condition: igore"); 00870 } 00871 //d->waitFrames(delayForSorting); 00872 playTone(tone2); 00873 d->waitFrames(30); 00874 00875 int spMemAns = spatial_memory_retrival(angles,dots_radius); 00876 switch( spMemAns ){ 00877 case 0: incorrectSPMMap[orientation_task_Vector.at(cr)]= incorrectSPMMap[orientation_task_Vector.at(cr)]+1;d->pushEvent("incorrect spatial memory answer");break; 00878 case 1: correctSPMMap[orientation_task_Vector.at(cr)]= correctSPMMap[orientation_task_Vector.at(cr)]+1;d->pushEvent("correct spatial memory answer");break; 00879 } 00880 00881 string ans1 = getDigitSequenceFromSubject("yn",1,"repeated?"); 00882 d->pushEvent("string answer to repeated question: "+ans1); 00883 00884 if((ans1.compare("y")==0 && twoBackTaskType== 1) || (ans1.compare("n")==0 && twoBackTaskType==0) ){ 00885 d->pushEvent("correct verbal task :)"); 00886 d->displayText(":)"); 00887 d->waitFrames(15); 00888 }else{ 00889 d->pushEvent("incorrect verbal task :("); 00890 d->displayText(":("); 00891 d->waitFrames(15); 00892 } 00893 00894 00895 cr++; 00896 } 00897 00898 d->pushEvent("horizontal, memory correct:"+stringify(correctSPMMap[0])); 00899 d->pushEvent("vertical, memory correct:"+stringify(correctSPMMap[1])); 00900 d->pushEvent("horizontal, memory incorrect:"+stringify(incorrectSPMMap[0])); 00901 d->pushEvent("vertical, memory incorrect:"+stringify(incorrectSPMMap[1])); 00902 00903 d->displayText("Experiment complete. Thank you!"); 00904 d->waitForMouseClick(); 00905 00906 // stop all our ModelComponents 00907 manager.stop(); 00908 00909 00910 // all done! 00911 return 0; 00912 } 00913 00914 #endif // INVT_HAVE_LIBSDL_IMAGE 00915