00001 /*!@file AppPsycho/psychoWM.C Psychophysics test to measure the influence of eyemovement on memory task performance */ 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/psychoWM-C.C $ 00035 // $Id: psychoWM-C.C 12962 2010-03-06 02:13:53Z irock $ 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 <stdio.h> 00059 #include <stdlib.h> 00060 #include <sstream> 00061 #include <time.h> 00062 #include "Image/DrawOps.H" 00063 #include "GameBoard/resize.h" 00064 #include <iostream> 00065 #include <fstream> 00066 #include <set> 00067 #include <algorithm> 00068 #include <ctime> 00069 #include "Devices/SimpleMotor.H" 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-Concurrent-Digit"); 00088 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager)); 00089 //nub::soft_ref<SimpleMotor> motor(new SimpleMotor(manager)); 00090 map<uint,uint> testMap ; 00091 map<string,string> argMap ; 00092 map<string,vector<SDL_Rect*>*> clipsmap; 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 00106 00107 bool itIsInThere(int x , vector<int> bag){ 00108 for( uint i=0 ; i < bag.size(); i++ ){ 00109 if(x == bag[i]) return true ; 00110 } 00111 return false ; 00112 } 00113 00114 00115 double getAvarage(vector<long> v){ 00116 double f = 0.0 ; 00117 for( uint i = 0 ; i < v.size() ; i++ ){ 00118 f += v[i] ; 00119 } 00120 if (v.size()!=0) return f/v.size() ; 00121 return -1 ; 00122 } 00123 00124 double getVariance(vector<long> v){ 00125 double m = getAvarage(v); 00126 double var = 0.0 ; 00127 for( uint i = 0 ; i < v.size(); i++ ){ 00128 var += (v[i]-m)*(v[i]-m) ; 00129 } 00130 if (v.size()!=0) return var/v.size() ; 00131 return -1 ; 00132 } 00133 00134 00135 00136 00137 00138 //////////////////////////////////////////////////////////////////// 00139 //// gets a string as the argument and returns a string composed of 00140 //// characters of the first string sorted in the ascending order 00141 /////////////////////////////////////////////////////////////////// 00142 string ascSort(string st) 00143 { 00144 string res = "" ; 00145 vector<string> v = vector<string>(); 00146 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00147 00148 std::sort(v.begin(), v.end()); 00149 00150 for ( uint i = 0 ; i < v.size() ; i++ ){ 00151 res += v[i] ; 00152 } 00153 return res; 00154 } 00155 00156 00157 00158 //////////////////////////////////////////////////////////////////// 00159 //// gets a string as the argument and returns a string composed of 00160 //// characters of the first string sorted in the descending order 00161 /////////////////////////////////////////////////////////////////// 00162 string desSort(string st) 00163 { 00164 string res = "" ; 00165 vector<string> v = vector<string>(); 00166 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ; 00167 std::sort(v.begin(), v.end()); 00168 std::reverse(v.begin(), v.end()); 00169 for ( uint i = 0 ; i < v.size() ; i++ ){ 00170 res += v[i] ; 00171 } 00172 return res; 00173 } 00174 00175 00176 ///////////////////////////////////////////////////////////// 00177 //this function checks how many subblocks of the sorted string can be found in 00178 //original string, the bigger chunks found the bigger number will be return 00179 //////////////////////////////////////////////////////////// 00180 00181 int mydist(string str , string sorted){ 00182 size_t found; 00183 int m = 0 ; 00184 for(uint i = 2 ; i <= sorted.size() ; i++ ){ 00185 for(uint j = 0 ; j <= sorted.size()-i ; j++ ) { 00186 found = str.find(sorted.substr(j,i)); 00187 if (found!=string::npos) m += i ; 00188 } 00189 } 00190 return m ; 00191 } 00192 00193 ///////////////////////////////////////////////////////////// 00194 //this function checks out the difficulty of sorting the string assigns a number which 00195 //reflects how many moves are needed for sorting, 00196 //////////////////////////////////////////////////////////// 00197 00198 int getDisMetric(string st){ 00199 int m = 0 ; 00200 size_t found; 00201 string asString = ascSort(st) ; 00202 for(uint i = 0 ; i < st.size() ; i++ ){ 00203 found = asString.find(st.substr(i,1)); 00204 m += abs((int)i-int(found)) ; 00205 } 00206 00207 return m- 2*mydist(st,asString) ; 00208 } 00209 00210 00211 00212 //////////////////////////////////////////////////////// 00213 ///// simply generates a sequence of digits with given alphabet with length of l with given threshold, if the given threshold is not achieved the best answer with 00214 //highest metric value in 1000000 times try will be returned 00215 //////////////////////////////////////////////////////// 00216 00217 string getARandomString(uint l, string alphabet="0123456789" , int thresh=0){ 00218 00219 string test = string("") ; 00220 string retString ; 00221 int maxDist = -1000000; 00222 int it = 0 ; 00223 int d = 0 ; 00224 do{ 00225 test = "" ; 00226 string tp = string("") ; 00227 vector<int> pickedones = vector<int>() ; 00228 for(uint i = 0 ; i < l ; i++){ 00229 int nd; 00230 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones) && pickedones.size() <= alphabet.size()) ; 00231 pickedones.push_back(nd); 00232 tp = alphabet.substr(nd,1) ; 00233 test += tp ; 00234 } 00235 it++ ; 00236 d = getDisMetric(test); 00237 maxDist=max(maxDist,d) ; 00238 if (d==maxDist) retString = test ; 00239 00240 }while( maxDist<thresh && it < 1000000); 00241 00242 return retString ; 00243 } 00244 00245 /////////////////////////////////////////////////////// 00246 //this function is not called in this program, but it generates a random string and it will show it in 00247 //a random place on the screen. 00248 ////////////////////////////////////////////////////// 00249 string digitMemorizationTask(uint l, string alphabet="0123456789" , int displayFrame = 10 ){ 00250 d->clearScreen() ; 00251 vector<int> pickedones = vector<int>() ; 00252 string test = string("") ; 00253 string tp = string("") ; 00254 for(uint i = 0 ; i < l ; i++){ 00255 int nd; 00256 do{ nd= rand()% alphabet.size() ; }while(itIsInThere(nd,pickedones) && pickedones.size() <= alphabet.size()) ; 00257 pickedones.push_back(nd); 00258 tp = alphabet.substr(nd,1) ; 00259 test += tp ; 00260 } 00261 d->displayText(test,true,0) ; 00262 d->waitFrames(displayFrame) ; 00263 d->clearScreen() ; 00264 return test ; 00265 } 00266 00267 00268 //////////////////////////////////////////////////////// 00269 ///////this will change the order of elements in a vector to a random order 00270 //////////////////////////////////////////////////////// 00271 void scramble(vector<string>& v){ 00272 vector<string> tv = vector<string>() ; 00273 while(v.size()>0){ 00274 tv.push_back(v[0]); 00275 v.erase(v.begin()); 00276 } 00277 int i = 0 ; 00278 while(tv.size()>0){ 00279 i = rand()%tv.size() ; 00280 v.push_back(tv[i]); 00281 tv.erase(tv.begin()+i); 00282 } 00283 } 00284 00285 00286 //////////////////////////////////////////////////////////////// 00287 ////This is our button factory 00288 //////////////////////////////////////////////////////////////// 00289 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){ 00290 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00291 textIm.clear(bgcolor); 00292 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor); 00293 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00294 Uint32 bc = d->getUint32color(bordercolor); 00295 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border); 00296 SDL_Surface* blank =getABlankSurface(size.i , size.j); 00297 SDL_Rect clip; 00298 clip.x = 0 ; 00299 clip.y = 0 ; 00300 clip.w = size.i ; 00301 clip.h = size.j ; 00302 apply_surface(0,0,*surf,*blank,clip); 00303 dumpSurface(surf) ; 00304 return blank ; 00305 } 00306 00307 //////////////////////////////////////////////////////////////////////// 00308 ////This is the function for creating the keypad, in fact it generates 00309 ////12 buttons and associates the actions to the region for each button 00310 //////////////////////////////////////////////////////////////////////// 00311 00312 SDL_Surface* getKeyPad(string alphabet,map<string , SDL_Rect>& buttmap){ 00313 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3); 00314 SDL_Rect clip; 00315 clip.x=0; 00316 clip.y=0; 00317 int numofrows = alphabet.size()/3 +1; 00318 if(alphabet.size()%3 != 0 ) numofrows++ ; 00319 int numofcolumns = 3 ; 00320 clip.w= pad->w / numofcolumns ; 00321 clip.h = pad->h / numofrows ; 00322 00323 //keys for 1 to 9 00324 for( int i = 0 ; i < numofrows*3 ; i++){ 00325 SDL_Surface* but ; 00326 if((uint)i < alphabet.size()){ 00327 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); 00328 }else{ 00329 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); 00330 } 00331 00332 SDL_Rect cl ; 00333 cl.x = ((i)%numofcolumns)*(pad->w)/numofcolumns ; cl.y= ((i)/numofcolumns)*((pad->h)/numofrows) ; 00334 cl.w = clip.w ; 00335 cl.h = clip.h ; 00336 apply_surface( cl.x , cl.y ,*but,*pad,clip); 00337 if((uint)i < alphabet.size()) buttmap[alphabet.substr(i,1)] = cl ; 00338 dumpSurface(but); 00339 } 00340 SDL_Rect cl1 ; 00341 cl1.x = 0 ; cl1.y= (numofrows-1)*((pad->h)/numofrows) ; 00342 cl1.w = clip.w ; 00343 cl1.h = clip.h ; 00344 buttmap["!"] = cl1 ; 00345 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); 00346 apply_surface(0, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00347 dumpSurface(but); 00348 SDL_Rect cl2 ; 00349 cl2.x = (pad->w)/numofcolumns ; cl2.y= (numofrows-1)*((pad->h)/numofrows) ; 00350 cl2.w = clip.w ; 00351 cl2.h = clip.h ; 00352 buttmap[" "] = cl2 ; 00353 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); 00354 apply_surface((pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00355 dumpSurface(but); 00356 SDL_Rect cl3 ; 00357 cl3.x = 2*(pad->w)/numofcolumns ; cl3.y= (numofrows-1)*((pad->h)/numofrows) ; 00358 cl3.w = clip.w ; 00359 cl3.h = clip.h ; 00360 buttmap["*"] = cl3 ; 00361 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); 00362 apply_surface(2*(pad->w)/numofcolumns, (numofrows-1)*((pad->h)/numofrows),*but,*pad,clip); 00363 dumpSurface(but); 00364 return pad ; 00365 } 00366 00367 00368 00369 00370 /////////////////////////////////////////////////////////////////////////// 00371 /////this function listens to mouse clicks and then finds the region of the screen 00372 /////associated with the action, buttmap is the map of the region, offset is the offset of 00373 /////buttons 00374 /////////////////////////////////////////////////////////////////////////// 00375 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){ 00376 int quit = 0 ; 00377 string s ; 00378 SDL_Event event ; 00379 while( quit!=2 ){ 00380 while( SDL_PollEvent( &event ) ) { 00381 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){ 00382 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){ 00383 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) { 00384 quit = 2 ; 00385 s = it->first ; 00386 break; 00387 } 00388 00389 } 00390 } 00391 00392 } 00393 } 00394 return s ; 00395 00396 } 00397 00398 00399 //////////////////////////////////////////////////// 00400 ////This function creates a virtual keypad, creates a map of buttons 00401 ////and their representation area and listens to the button press and at 00402 ////the end returns the keyed digits 00403 //////////////////////////////////////////////////// 00404 string getDigitSequenceFromSubject(string alphabet="0123456789" , uint maxl = 7 ){ 00405 d->showCursor(true) ; 00406 //let's creat a map to map actions to regions of the screen, each region is represented as an SDL_Rect 00407 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>(); 00408 //now let's get the keypad surface while we get the actions map to regions 00409 SDL_Surface * keypad = getKeyPad(alphabet,*buttmap); 00410 //this will be the offset of displaying the keypad on the screen 00411 SDL_Rect offset ; 00412 offset.x = (d->getWidth() - keypad->w) /2; 00413 offset.y = (d-> getHeight() - keypad->h) /2; 00414 //now let's display the keypad 00415 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true); 00416 //this will hold the final string keyed be the subject 00417 string p = string("") ; 00418 //this is a temporary string holding the last action related to the pressed key 00419 string tp = string(""); 00420 //now let's record subject's key press 00421 while( tp.compare("*")!=0 ){ 00422 //this button is actually the display for the current string 00423 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) ; 00424 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ; 00425 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ; 00426 //now let's listen to button events 00427 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ; 00428 dumpSurface(dp) ; 00429 if(tp.compare("!")==0 && p.size()>=0 ) { 00430 if (p.size()>0) p = p.substr(0,p.size()-1) ; 00431 }else{ 00432 if(p.size() < maxl && tp.compare("*")!=0) { 00433 p +=tp ; 00434 } 00435 00436 } 00437 00438 } 00439 buttmap = 0 ; 00440 dumpSurface(keypad) ; 00441 d->clearScreen() ; 00442 return p ; 00443 00444 } 00445 00446 //and this is the function which creates and displays a mask of randomly positioned numbers 00447 void showMask(int frames, string alphabet="0123456789"){ 00448 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS); 00449 PixRGB<byte> bgcolor = PixRGB<byte>(128,128,128); 00450 PixRGB<byte> txtcolor = PixRGB<byte>(0,0,0); 00451 textIm.clear(bgcolor); 00452 for(int i = 0 ; i < 200 ; i++) 00453 writeText(textIm, Point2D<int>((int)random()%(d->getWidth()),(int)random()%(d->getHeight())),alphabet.substr(random()%(int)alphabet.size(),1).c_str(),txtcolor,bgcolor); 00454 SDL_Surface *surf = d->makeBlittableSurface(textIm , true); 00455 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00456 d->displaySDLSurfacePatch(surf , &offs , NULL , -2 , false ,true ) ; 00457 d->waitFrames(frames) ; 00458 d->clearScreen(); 00459 dumpSurface(surf) ; 00460 } 00461 /////////////////////////////////////////////////////////////// 00462 //////gets the test string, answer and the mode and identifies if 00463 //////the answer matches the thing it should be, mode=0 checks if 00464 //////if the answer and test string simply the same, mode=1 matches 00465 //////the answer against the ascending sorted string of the test string 00466 //////mode=2 compares the answer against the descending sorted of 00467 //////the test string 00468 /////////////////////////////////////////////////////////////// 00469 bool isAnswerCorrect(string test , string answer , int mode){ 00470 00471 if(mode == 0 && answer.compare(test)==0) return true ; 00472 00473 if(mode == 1 && answer.compare(ascSort(test))==0) return true ; 00474 00475 if(mode == 2 && answer.compare(desSort(test))==0) return true ; 00476 00477 return false; 00478 } 00479 00480 00481 00482 int addArgument(const string st,const string delim="="){ 00483 int i = st.find(delim) ; 00484 argMap[st.substr(0,i)] = st.substr(i+1); 00485 00486 return 0 ; 00487 } 00488 00489 std::string getArgumentValue(string arg){ 00490 return argMap[arg] ; 00491 } 00492 00493 std::string getUsageComment(){ 00494 00495 string com = string("\nlist of arguments : \n"); 00496 com += "\nlogfile=[logfilename.psy] {default = psycho-wm-cc.psy}\n" ; 00497 com += "\nmemo=[a_string_without_white_space]\n"; 00498 com += "\nstring-size=[>0](the size of string){default=5} \n"; 00499 com += "\nsubject=[subject_name] \n" ; 00500 com += "\ntest-rounds=[>1] (number of tests ) {default=10}\n"; 00501 com += "\ndigit-onset=[>1] (number of frames that the string will remain onset ){default=10}\n"; 00502 com += "\nalphabet=[a string of characters](a string of characters){default=0123456789}\n"; 00503 com += "\nmetric-thresholdt=[>-30 for string of lenght of 5](a string of characters){default=10}\n"; 00504 com += "\nmaintain-prb=[a number between 0 to 1], probability of challenging the subject with a memorization task, default=0.2\n" ; 00505 com += "\nball-radius={0>}(radius of the ball){default=-1 which means the ball will be positioned in the given place with the given aspect ration}\n" ; 00506 com += "\nball-position=[x-y](x and y are position of the center of the ball){default is x=w/2 and y=h/2}\n" ; 00507 com += "\nmin-reaction-time=[>0](minimum value for avarage reaction time in microsecond in order to consider a trial valid){default=1000000}\n" ; 00508 com += "\nmax-miss=[>0](maximum misses in a trial in order to be considered as a valid one){default=0}"; 00509 com += "\nmax-false-click=[>0](maximum false clicks in a trial in order to be considered as a valid one){default=0}"; 00510 com += "\ninterrupt-time-range=[x-y](this defines a range of uniform radom distribution by which the perceptual interruption happens){default=500000-5000000}\n" ; 00511 com += "\nrgb1=[r-g-b]{default=50-91-255}\n"; 00512 com += "\nrgb2=[r-g-b]{default=89-122-255}\n"; 00513 com += "\nrgb3=[r-g-b]{default=138-159-255}\n"; 00514 com += "\ncue-wait-frames=[<0](number of frames to show the cue){default=0}\n"; 00515 com += "\ncue-onset-frames=[<0](number of frames to show the cue onset){default=3}\n"; 00516 com += "\nmask=[y/n](whether present a mask after presentation, n for no, y for yes ){default=n}\n" ; 00517 com += "\nmask-onset-frames=[<0](number of frames that mask will be onset){default=0}\n"; 00518 return com ; 00519 } 00520 00521 int myCheckForMouseClick() 00522 { 00523 SDL_Event event; 00524 00525 while(SDL_PollEvent(&event)) 00526 { 00527 if (event.type == SDL_MOUSEBUTTONDOWN) 00528 { 00529 if(event.button.button == SDL_BUTTON_LEFT) { 00530 return 1 ; 00531 } 00532 if(event.button.button == SDL_BUTTON_RIGHT) { 00533 return 2 ; 00534 } 00535 00536 } 00537 // ignore other events 00538 } 00539 00540 // there was no event in the event queue: 00541 return -1; 00542 } 00543 00544 00545 int getClick(){ 00546 // while (myCheckForMouseClick() != -1) ; 00547 SDL_Event event; 00548 bool report = false ; 00549 int i = 0; // will be returned if any other button than left or right 00550 do { 00551 do { SDL_WaitEvent(&event); } while (event.type != SDL_MOUSEBUTTONDOWN); 00552 if (event.button.button == SDL_BUTTON_LEFT) { 00553 i = 0 ; 00554 report = true ; 00555 } 00556 if (event.button.button == SDL_BUTTON_RIGHT) { 00557 i = 1 ; 00558 report = true ; 00559 } 00560 00561 }while(!report) ; 00562 00563 return i ; 00564 } 00565 00566 int getAllKindOfClick(){ 00567 // while (myCheckForMouseClick() != -1) ; 00568 SDL_Event event; 00569 bool report = false ; 00570 int i = 0; // will be returned if any other button than left or right 00571 do { 00572 do { SDL_WaitEvent(&event); } while (event.type != SDL_MOUSEBUTTONDOWN); 00573 long st = d->getTimerValue(); 00574 long et = st ; 00575 00576 if (event.button.button == SDL_BUTTON_LEFT) { 00577 i = 0 ; 00578 report = true ; 00579 while( et-st < 300000){ 00580 et = d->getTimerValue() ; 00581 if(myCheckForMouseClick()==1) return 2 ; 00582 } 00583 } 00584 if (event.button.button == SDL_BUTTON_RIGHT) { 00585 i = 1 ; 00586 report = true ; 00587 } 00588 00589 }while(!report) ; 00590 00591 return i ; 00592 00593 } 00594 00595 int getNext(int i){ 00596 00597 int r = 1 ; 00598 if(i == 0 || i == 2) return 1 ; 00599 r = random()%2 ; 00600 if(r == 0) return 0 ; 00601 if(r == 1 ) return 2 ; 00602 return r ; 00603 } 00604 00605 vector<long> getInterrunptVector(long minIntVal=500000 , long maxIntVal=2000000 , uint rep=10){ 00606 vector<long> tempVector; 00607 vector<long> intVector; 00608 for (uint i = 0 ; i < rep ; i++){ 00609 while( tempVector.size() < i+1 ){ 00610 long tl = random()%(rep*maxIntVal) ; 00611 bool flag = true ; 00612 for(uint j = 0 ; j < tempVector.size() ; j++ ){ 00613 if(abs(tl-tempVector[j]) < minIntVal) flag = false ; 00614 } 00615 if(flag) tempVector.push_back(tl) ; 00616 } 00617 } 00618 std::sort(tempVector.begin(), tempVector.end()); 00619 long in = 0 ; 00620 for( uint i = 0 ; i < tempVector.size() ; i++ ){ 00621 intVector.push_back(tempVector[i] - in) ; 00622 in = tempVector[i] ; 00623 } 00624 intVector.push_back(922036854797);//this is a the last interrupt which is set to a big number 00625 return intVector ; 00626 } 00627 00628 00629 extern "C" int main(const int argc, char** argv) 00630 { 00631 00632 MYLOGVERB = LOG_INFO; // suppress debug messages 00633 //let's push the initial value for the parameters 00634 argMap["experiment"]="sorting_strings_in_working_memory-with-color-presentation"; 00635 argMap["logfile"]="psycho-wm-cc.psy" ; 00636 argMap["string-size"]="5" ; 00637 argMap["test-rounds"]="10"; 00638 argMap["subject"]="" ; 00639 argMap["memo"]="" ; 00640 argMap["digit-onset"]="10" ; 00641 argMap["alphabet"]="0123456789"; 00642 argMap["metric-threshold"]="10" ; 00643 argMap["maintain-prb"]="0.2" ; 00644 argMap["ball-radius"] = "-1" ; 00645 argMap["ball-position"]="0" ; 00646 argMap["min-reaction-time"]="1000000" ; 00647 argMap["max-miss"]="0" ; 00648 argMap["interrupt-time-range"]= "500000-5000000"; 00649 argMap["rgb1"]="50-91-255" ; 00650 argMap["rgb2"]="89-122-255" ; 00651 argMap["rgb3"]="138-159-255" ; 00652 argMap["cue-wait-frames"]="0" ; 00653 argMap["mask"]="n" ; 00654 argMap["mask-onset-frames"]="0"; 00655 argMap["cue-onset-frames"] = "3" ; 00656 argMap["max-false-click"]="0"; 00657 manager.addSubComponent(d); 00658 //manager.addSubComponent(motor) ; 00659 nub::soft_ref<EventLog> el(new EventLog(manager)); 00660 manager.addSubComponent(el); 00661 d->setEventLog(el); 00662 //mmanager.parseCommandLine(argc, argv, "", 0,0); 00663 //mmanager.start(); 00664 00665 if (manager.parseCommandLine(argc, argv, 00666 "at least one argument needed", 1, -1)==false){ 00667 cout<<getUsageComment()<<endl; 00668 return(1); 00669 } 00670 00671 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){ 00672 addArgument(manager.getExtraArg(i),std::string("=")) ; 00673 } 00674 00675 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]); 00676 00677 00678 00679 // let's get all our ModelComponent instances started: 00680 manager.start(); 00681 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ; 00682 00683 int x = 0 ; int y = 0 ; int rad = 0 ; 00684 if(argMap["ball-position"].compare("0")==0){ 00685 x = d->getWidth()/2 ; 00686 y = d->getHeight() /2 ; 00687 }else{ 00688 int in = argMap["ball-position"].find("-") ; 00689 x = atoi( argMap["ball-position"].substr(in+1).c_str()) ; 00690 y = atoi(argMap["ball-position"].substr(0,in).c_str()) ; 00691 } 00692 00693 if(argMap["ball-radius"].compare("-1") == 0){ 00694 rad = min(min(y-1,d->getHeight()-y-1),min(x,d->getWidth()-x-1)) ; 00695 }else{ 00696 rad = atoi(argMap["ball-radius"].c_str()) ; 00697 rad = min(rad, min(min(y-1,d->getHeight()-y-1),min(x,d->getWidth()-x-1))) ; 00698 } 00699 00700 SDL_Surface* surf1 = getABlankSurface(d->getWidth(),d->getHeight()); 00701 SDL_Surface* surf2 = getABlankSurface(d->getWidth(),d->getHeight()); 00702 SDL_Surface* surf3 = getABlankSurface(d->getWidth(),d->getHeight()); 00703 SDL_Surface* black = getABlankSurface(d->getWidth(),d->getHeight()); 00704 string rgb1 = argMap["rgb1"] ; 00705 string rgb2 = argMap["rgb2"] ; 00706 string rgb3 = argMap["rgb3"] ; 00707 Uint32 color1 = d->getUint32color(PixRGB<byte>(atoi(rgb1.substr(0,rgb1.find_first_of("-")).c_str()), atoi(rgb1.substr(rgb1.find_first_of("-")+1,rgb1.find_last_of("-")-rgb1.find_first_of("-")-1).c_str()), atoi(rgb1.substr(rgb1.find_last_of("-")+1).c_str()))); 00708 Uint32 color2 = d->getUint32color(PixRGB<byte>(atoi(rgb2.substr(0,rgb2.find_first_of("-")).c_str()), atoi(rgb2.substr(rgb2.find_first_of("-")+1,rgb2.find_last_of("-")-rgb2.find_first_of("-")-1).c_str()), atoi(rgb2.substr(rgb2.find_last_of("-")+1).c_str()))); 00709 Uint32 color3 = d->getUint32color(PixRGB<byte>(atoi(rgb3.substr(0,rgb3.find_first_of("-")).c_str()), atoi(rgb3.substr(rgb3.find_first_of("-")+1,rgb3.find_last_of("-")-rgb3.find_first_of("-")-1).c_str()), atoi(rgb3.substr(rgb3.find_last_of("-")+1).c_str()))); 00710 fillCubicRadiant(surf1,color1,x,y,rad) ; 00711 fillCubicRadiant(surf2,color2,x,y,rad) ; 00712 fillCubicRadiant(surf3,color3,x,y,rad) ; 00713 vector<SDL_Surface*> surfVector; 00714 surfVector.push_back(surf1) ; 00715 surfVector.push_back(surf2) ; 00716 surfVector.push_back(surf3) ; 00717 SDL_Rect offs ; offs.x = 0 ; offs.y = 0 ; 00718 00719 // let's display an ISCAN calibration grid: 00720 d->clearScreen(); 00721 d->displayISCANcalib(); 00722 d->waitForMouseClick(); 00723 d->displayText("Here the experiment starts! click to start!"); 00724 d->waitForMouseClick(); 00725 d->clearScreen(); 00726 //let's see in what mode the user like to run the program 00727 00728 int numOfTests = atoi(argMap["test-rounds"].c_str()) ; 00729 int stringSize = atoi(argMap["string-size"].c_str()); 00730 int meticThreshold = atoi(argMap["metric-threshold"].c_str()) ; 00731 int onsetDel = atoi(argMap["digit-onset"].c_str()) ; 00732 float memPrb = atof(argMap["maintain-prb"].c_str()) ; 00733 int max_miss = atoi(argMap["max-miss"].c_str()); 00734 int max_wrong = atoi(argMap["max-false-click"].c_str()) ; 00735 int in = argMap["interrupt-time-range"].find("-") ; 00736 long iub = atol(argMap["interrupt-time-range"].substr(in+1).c_str()); 00737 long ilb = atol(argMap["interrupt-time-range"].substr(0,in).c_str()) ; 00738 long min_reaction_time = atol(argMap["min-reaction-time"].c_str()) ; 00739 int cue_onset_frames = atoi(argMap["cue-onset-frames"].c_str()) ; 00740 int cue_wait_frames = atoi(argMap["cue-wait-frames"].c_str()) ; 00741 int mask_onset_frames = atoi(argMap["mask-onset-frames"].c_str()) ; 00742 00743 //let's count the rounds 00744 int cr = 0 ; 00745 int fm =0 ; //keeps number of failed memory tests 00746 int sm = 0 ; //keeps number of successful memory tests 00747 int ssfr=0 ; //keeps number of successful sorts but failed reactions 00748 int fssr=0 ; //keeps number of failed sorting and suuccessful reaction 00749 int sssr=0 ; //keeps number of successful sorting and successful reaction 00750 int fsfr=0 ; //keeps number of failed sorting and failed reactions 00751 vector<long> correctAnswersTiming; 00752 vector<long> incorrectAnswersTiming; 00753 vector<long> allTiming ; 00754 while( cr <numOfTests ){ 00755 float mP = (float) rand()/RAND_MAX ; 00756 if(mP > memPrb){ 00757 00758 d->pushEvent("**************************************") ; 00759 d->showCursor(true); 00760 d->displayText("click one of the mouse buttons to start!"); 00761 d->waitForMouseClick() ; 00762 d->showCursor(false) ; 00763 string testString ; 00764 vector<long> reactionTimes ; 00765 testString = getARandomString(stringSize, argMap["alphabet"] , meticThreshold);// digitMemorizationTask(stringSize, argMap["alphabet"] , wr , hr , onsetDel) ; 00766 d->clearScreen() ; 00767 d->displayFixationBlink(); 00768 d->displayText(testString,true,0) ; 00769 d->waitFrames(onsetDel) ; 00770 d->clearScreen() ; 00771 if(argMap["mask"].compare("y")==0) showMask(mask_onset_frames,argMap["alphabet"]); 00772 if(cue_wait_frames != 0) d->waitFrames(cue_wait_frames) ; 00773 d->displayRedDotFixation(); 00774 d->waitFrames(cue_onset_frames); 00775 long st = d->getTimerValue() ; 00776 d->clearScreen() ; 00777 d->pushEvent("manipulation starts"); 00778 d->pushEvent("the sequence for manipulation is : "+testString) ; 00779 00780 long tst =0 ; 00781 long tet =0 ; 00782 00783 int cs = 0 ; 00784 d->displaySDLSurfacePatch(surfVector[cs] , &offs , NULL , -2 , false ,true ) ; 00785 long dst = 0 ; 00786 long det = 0 ; 00787 long dl = 0 ; 00788 dl = ilb+ random() % (iub-ilb);//we get a value for next stop 00789 dst = d->getTimerValue() ; 00790 det = dst ; 00791 int missed = 0 ; 00792 bool exitFlag = false ; 00793 bool clickFlag = false ; 00794 int ms = -1 ;//holds mouseclick status 00795 int wrongclick = 0 ; 00796 vector<long> interruptsVector = getInterrunptVector(ilb,iub,500); 00797 int ind = 0 ; 00798 dl = interruptsVector[ind] ;ind++ ; 00799 while( !exitFlag ){ 00800 00801 if (det - dst > dl ){ 00802 cs = getNext(cs) ; 00803 d->displaySDLSurfacePatch(surfVector[cs] , &offs , NULL , -2 , false ,true ) ; 00804 tst = d->getTimerValue() ; 00805 det=tst ; 00806 if(clickFlag){ 00807 missed++ ; 00808 d->pushEvent("missed one change"); 00809 } 00810 clickFlag=true ; 00811 dst = det ; 00812 dl = interruptsVector[ind] ;ind++ ; 00813 //dl = ilb+ random() % (iub-ilb);//we get a value for next stop 00814 } 00815 ms = myCheckForMouseClick() ; 00816 if(ms==2) exitFlag = true ; 00817 det = d->getTimerValue() ; 00818 00819 if(clickFlag && ms==1){ 00820 clickFlag = false ; 00821 tet = d->getTimerValue() ; 00822 reactionTimes.push_back(tet-tst); 00823 d->pushEvent("reaction time :" + stringify(tet-tst)); 00824 }else{if(ms==1) wrongclick++ ;} 00825 } 00826 00827 long et = d->getTimerValue(); 00828 d->pushEvent("manipulation ends") ; 00829 d->pushEvent("maniupulation time : "+stringify(et-st)) ;allTiming.push_back(et-st); 00830 d->clearScreen(); 00831 string answer = getDigitSequenceFromSubject(argMap["alphabet"] , testString.size()); 00832 00833 bool af = false ; 00834 af = isAnswerCorrect(testString,answer,1); 00835 d->pushEvent("subject keyed : "+answer); 00836 d->pushEvent("avarage reaction time : "+ stringify(getAvarage(reactionTimes))) ; 00837 d->pushEvent("number of missed events : "+stringify(missed)); 00838 d->pushEvent("number of caught events : "+stringify(reactionTimes.size())) ; 00839 if(missed <= max_miss && getAvarage(reactionTimes)<= min_reaction_time && wrongclick <= max_wrong){ 00840 cr++; 00841 d->pushEvent("valid trial"); 00842 if(af){ 00843 d->pushEvent("answer was correct");sssr++;correctAnswersTiming.push_back(et-st) ; 00844 }else{ 00845 d->pushEvent("answer was incorrect");fssr++; 00846 } 00847 }else{ 00848 if(wrongclick > max_wrong) { 00849 d->displayText("Trial failed, too many FALSE REPORT! Click to start over!"); 00850 d->waitForMouseClick(); 00851 } 00852 if(missed > max_miss) { 00853 d->displayText("Trial failed, too many events missed! Click to start over!"); 00854 d->waitForMouseClick(); 00855 } 00856 if(getAvarage(reactionTimes) > min_reaction_time){ 00857 d->displayText("Trial failed, reaction slower than limit! Click to start over!"); 00858 d->waitForMouseClick(); 00859 } 00860 if(af){ 00861 d->pushEvent("answer was correct");ssfr++; 00862 }else{ 00863 d->pushEvent("answer was incorrect");fsfr++; 00864 } 00865 d->pushEvent("invalid trial"); 00866 } 00867 00868 }else{ 00869 d->pushEvent("+++++++++++++++++++++++++++++++++++++++") ; 00870 d->showCursor(true); 00871 d->displayText("click one of the mouse buttons to start!"); 00872 d->waitForMouseClick() ; 00873 d->showCursor(false) ; 00874 string testString ; 00875 testString = getARandomString(stringSize, argMap["alphabet"] , meticThreshold);// digitMemorizationTask(stringSize, argMap["alphabet"] , wr , hr , onsetDel) ; 00876 d->clearScreen() ; 00877 d->displayFixationBlink(); 00878 d->displayText(testString,true,0) ; 00879 d->waitFrames(onsetDel) ; 00880 d->clearScreen() ; 00881 if(argMap["mask"].compare("y")==0) showMask(mask_onset_frames,argMap["alphabet"]); 00882 if(cue_wait_frames != 0) d->waitFrames(cue_wait_frames) ; 00883 d->displayFixationBlink(d->getWidth()/2,d->getHeight()/2,1,3); 00884 d->pushEvent("the memorization sequence is : "+testString) ; 00885 00886 d->pushEvent("subject is being challenged for simple momorization"); 00887 d->clearScreen(); 00888 00889 string answer = getDigitSequenceFromSubject(argMap["alphabet"] , testString.size()); 00890 00891 bool af = false ; 00892 af = isAnswerCorrect(testString,answer,0); 00893 d->pushEvent("subject keyed : "+answer); 00894 if(af){ 00895 d->pushEvent("correct answer"); 00896 sm++; 00897 }else{ 00898 d->pushEvent("incorrect answer"); 00899 fm++ ; 00900 } 00901 00902 } 00903 } 00904 00905 d->pushEvent("number of successful memory tests :" + stringify(sm)); 00906 d->pushEvent("number of failed memory tests :" + stringify(fm)) ; 00907 d->pushEvent("number of successful sorting and successful reaction trials :"+stringify(sssr)); 00908 d->pushEvent("number of successful sorting and failed reaction trials :"+stringify(ssfr)); 00909 d->pushEvent("number of failed sorting and successful reaction trials :"+stringify(fssr)); 00910 d->pushEvent("number of failed sorting and failed reaction trials :"+stringify(fsfr)); 00911 d->pushEvent("avarage time for respond :"+ stringify(getAvarage(allTiming))); 00912 d->pushEvent("variance of respond :"+ stringify(getVariance(allTiming))); 00913 d->pushEvent("avarage time for correct answers "+stringify(getAvarage(correctAnswersTiming))) ; 00914 d->pushEvent("variance of correct responds :"+ stringify(getVariance(correctAnswersTiming))); 00915 dumpSurface(surf1) ; 00916 dumpSurface(surf2) ; 00917 dumpSurface(surf3) ; 00918 dumpSurface(black) ; 00919 d->clearScreen(); 00920 d->displayText("Experiment complete. Thank you!"); 00921 d->waitForMouseClick(); 00922 00923 // stop all our ModelComponents 00924 manager.stop(); 00925 00926 00927 // all done! 00928 return 0; 00929 } 00930 00931 #endif // INVT_HAVE_LIBSDL_IMAGE 00932