7

I'm using Psychtoolbox in MATLAB to run a behavioral psychology paradigm. As part of the paradigm, users have to view a visual stimulus and respond to it using some input mechanism. For a keyboard, this works as follows:

  1. show stimulus
  2. poll keyboard for response
    1. if no response detected, loop back to 1
    2. if response detected, break and move on with script

This works fine for a keyboard, as step 2 takes between 1-2 ms. The problem comes when I use an alternate input mechanism; in that case, step 2 takes ~20 ms. (I need this alternate input to run the study, and that should be considered immutable fact.) As the stimulus changes with a very short timespan, this added delay breaks the task.

My current thought is to try to use the parallel processing, such that one thread shows the stimulus, and another thread polls the keyboard. I'm currently using the Parallel Computing Toolbox to do this. The problem I'm having is that I don't know how to direct keyboard input to a "parallelized" thread. Does anyone know (1) whether it's possible to direct keyboard input to a thread / have a thread send a visual signal to a monitor, and if yes, (2) how to do it?

Also, if anyone has any better ideas as to how to approach this problem, I'm all ears.

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
eykanal
  • 26,437
  • 19
  • 82
  • 113
  • I'm a little confused. Are you wanting to show one stimulus, wait a preset amount of time for any response from the user, then show another stimulus in they haven't responded (or break the loop if they have)? Also, how exactly does the delay "break" the task? – gnovice Dec 10 '10 at 17:15
  • @gnovice - No, I want to show (and continually update) one stimulus, and only stop showing (updating) it when a response is given. How the delay breaks it is kind of detailed, but suffice to say the screen needs to be refreshing on the order of every 5-8 ms, and the additional 20 ms delay is too long. – eykanal Dec 10 '10 at 18:20
  • So, I guess you have an animated stimulus if you need to update it continuously, but every 5-8 msec would be a frame rate of 125-200 Hz. Does it really have to be that fast? A typical frame rate of 60 Hz is usually good enough to avoid flickering. – gnovice Dec 10 '10 at 18:34
  • @gnovice - Unfortunately, this is a pretty complex stimulus, and it does need to be that quick. As I can't well show you the stimulus, you'll have to believe me that the difference is both noticeable and unacceptable for research purposes. – eykanal Dec 10 '10 at 18:44
  • Understood, I'm in research myself. One additional question (if you are allowed to answer ;) ): What is the alternate input device and how are you polling it from MATLAB? – gnovice Dec 10 '10 at 19:53
  • @gnovice - Definitely! We're using the [MCC USB-1208](http://www.mccdaq.com/usb-data-acquisition/USB-1208FS.aspx) data acquisition device. Long story short, a subject sits in a brain scanner and responds via single-button pads, which have a parallel out cable. I hooked the cable up to this device, and MATLAB can poll this device to see whether responses were made. – eykanal Dec 10 '10 at 19:58

3 Answers3

4

According to this MATLAB newsgroup thread, it appears that threads can't modify graphics objects. Only the desktop MATLAB client can do that. This means that you can't handle updating of graphics from a thread, and I can confirm this as I tried it and wasn't able to modify figures or even the root object from a thread.

However, I think you may be able to do the main graphics updating in MATLAB while a thread handles polling for your input. Here's a sample function for continuously updating a display until a thread waiting for input from KbCheck is finished running:

function varargout = plot_until_input

  obj = createJob();                                   %# Create a job
  task = createTask(obj,@get_input,4,{deviceNumber});  %# Create a task
  submit(obj);                                         %# Submit the job
  waitForState(task,'running');  %# Wait for the task to start running

  %# Initialize your stimulus display here
  while ~strcmp(get(task,'State'),'finished')  %# Loop while the task is running
    %# Update your stimulus display here
  end

  varargout = get(task,'OutputArguments');  %# Get the outputs from the task
  destroy(obj);                             %# Remove the job from memory

%#---Nested functions below---

  function [keyIsDown,secs,keyCode,deltaSecs] = get_input(deviceNumber)
    keyIsDown = false;
    while ~keyIsDown  %# Keep looping until a key is pressed
      [keyIsDown,secs,keyCode,deltaSecs] = KbCheck(deviceNumber);
    end
  end

end

I was able to successfully run the above function with some simple plotting routines and replacing the code in get_input with a simple pause statement and a return value. I'm unsure whether KbCheck will work in a thread, but hopefully you will be able to adapt this for your needs.

Here's the documentation for the Parallel Computing Toolbox functions used in the above code: createJob, createTask, submit, waitForState, destroy.

gnovice
  • 125,304
  • 15
  • 256
  • 359
  • 1
    I'm using a toolbox called [PsychToolbox](http://psychtoolbox.org/), they have a pretty sophisticated function `KbCheck` which uses mex functions for this sort of thing. Also, they have their own screen draw functions, and don't use the builtin plot functions (at least, not directly). Thanks, though. – eykanal Dec 10 '10 at 19:55
  • Don't know why the downvote, but a +1 from me for the nifty idea. I wasnt aware of the different `wateforstate` options. I'll try it when I get back to work on Monday and give more feedback then. Thanks! – eykanal Dec 12 '10 at 01:50
  • 1
    So, using the `inspect` function, it looks like the `KbCheck` function is generating a `MATLAB:UndefinedFunction - Undefined function handle` error message. This question is being continued [here](http://stackoverflow.com/questions/4424268/load-external-toolbox-to-a-parallel-computing-toolkit-job). – eykanal Dec 12 '10 at 21:53
  • This is good. Could you run the code? I am interested in it also. Add '+1' for gnovice for me (I still can't vote.) – Y.T. Dec 14 '10 at 17:55
  • @Y.T.: Actually, with [66 Rep you should be able to vote now](http://stackoverflow.com/privileges). Well, you can *upvote*, but you need 100 to *downvote*. – gnovice Dec 14 '10 at 18:03
2

I don't know of a way how you could do this with parallel processing.

However, a feature you might be able to use is the timer object. You would set up the timer object to poll the input mechanism, and, if anything is detected, change the value of a global variable. Then, you start your stimulus routine. In the while-loop in which you're updating the display, you keep checking the global variable for a change from the timer object.

Jonas
  • 74,690
  • 10
  • 137
  • 177
  • In my case, though, I need to be continually updating the stimulus WHILE polling the input mechanism. Unless I'm missing something, this approach doesn't allow for continuous stimulus updating, due to the `uiwait` call. – eykanal Dec 10 '10 at 19:13
  • @eykanal: Now I understand. Yes, this would not work with figures/uiwait, but if the timer object changes the value of a global variable, it could work. One would have to test whether it was fast enough. – Jonas Dec 11 '10 at 03:37
-2

You have to tackle the 20ms latency in your input device. If it's too slow then get another input device. You can get good sub-millisecond timing with proper response boxes.

All this talk about threading is misguided and not applicable to the PTB framework.

towolf
  • 350
  • 1
  • 6
  • 2
    "Get another input device" is almost always a bad answer, as often (including in my case) you're limited to a specific kind of input device. It happens that the threading solution has worked, so it is definitely applicable to the PTB framework. – eykanal Feb 09 '11 at 20:29