PROPixx Demo 4 – Drawing dots at 1440 Hz with automatic quadrant assignment

This demo is a simple demonstration of the PROPixx’s 1440 Hz sequencer. We display a white dot rotating in a circle around the middle of the display, refreshing at 1440 Hz. This demo uses Psychtoolbox’s PsychProPixx functions to automate quadrant and color channel assignment.

To display images at 1440 Hz, the PROPixx uses a sequencer to break up a 1920 x 1080 120 Hz RGB video signal into 12 individual frames. The 1920 x 1080 image is first divided into quadrants, which are magnified to full screen. Each 8-bit RGB color channel is then converted to grayscale. The order of frame presentation is: Q1 red, Q2 red, Q3 red, Q4 red, Q1 green, Q2 green, Q3 green, Q4 green, Q1 blue, Q2 blue, Q3 blue, Q4 blue. Below is a visual representation of this process:

_images/Quad12xStill.png

In our previous DrawDots demos, we manually assigned our stimuli to the correct quadrant and color channel of the 1920 x 1080 display, so that the stimuli appeared in the correct order on the 1440 Hz display. PsychProPixx automates this process. To generate our stimuli we simply do the following:

  1. Create an offscreen 960 x 540 image with PsychProPixx('GetImageBuffer')

  2. Draw our frame contents to this image

  3. Add the image to a queue using PsychProPixx('QueueImage')

  4. When 12 frames have been added to the queue, PsychProPixx constructs a 1920 x 1080 RGB image and flips it to the display. The sequencer then displays the frames one after the other.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
function PPxDraw1440HzDots3
%This function draws a moving dot refreshing at 1440Hz. It demonstrates how
%to use the Psychtoolbox-3 function 'PsychPropixx' to queue and display
%frames. For documentation of this function, see
%"http://psychtoolbox.org/docs/PsychProPixx"

%Please note this function is maintained by the creators of Psychtoolbox.
%For demos showing how to drive the projector with VPixx Technologies' own
%Datapixx functions, please see PPxDraw1440HzDots and PPxDraw1440HzDots2

% To display at 1440 Hz, the PROPixx sequences takes a single 1920 x 1080
% image and deconstructs it in to four 960 x 540 quadrants.
%_____________________________
%|             |             |
%|     Q1      |      Q2     |
%|_____________|_____________|
%|             |             |
%|     Q3      |      Q4     |
%|_____________|_____________|  


%Quadrants are shown FULL SCREEN, GREYSCALE in the order: 
% Quadrant 1 red channel 
% Quadrant 2 red channel
% Quadrant 3 red channel
% Quadrant 4 red channel
% Quadrant 1 green channel
% Quadrant 2 green channel
% Quadrant 3 green channel
% Quadrant 4 green channel
% Quadrant 1 blue channel 
% Quadrant 2 blue channel 
% Quadrant 3 blue channel
% Quadrant 4 blue channel

%PsychPropixx('GetImageBuffer') creates a 960 x 540 image buffer which can
%be used to draw images. These are added to the frame queue using
%PsychProPixx('QueueImage'), and their position and colour channel are
%automatically assigned based on queue order. When the right number of
%frames is reached (12 in 1440 Hz mode, or 4 in 480 Hz mode), the queue
%contents are flipped automatically. 

% 2020 Apr 06       lef     written

%Check connection and open Datapixx if it's not open yet
isConnected = Datapixx('isReady');
if ~isConnected
    Datapixx('Open');
end

%Open a display on the Propixx
AssertOpenGL;
KbName('UnifyKeyNames');
screenID = 2;                                           %Change this value to change display
[windowPtr,~] = Screen('OpenWindow', screenID, 0);

%Enable 1440 Hz mode (12 frames/flip), with sync flipping
Datapixx('SetPropixxDlpSequenceProgram', 5);
Datapixx('RegWrRd');

PsychProPixx('SetupFastDisplayMode', windowPtr, 12, 0);   
stimulusBuffer = PsychProPixx('GetImageBuffer');

%Set up some stimulus characteristics-- remember the final display will be
%halved resolution
dotRadius = 10;
dotColour = [255, 255, 255];
bkgColour = [0,0,0];
targetRadius = 100;
center = [960/2, 540/2];

%Predefine stim positions to increase speed. Number of angles should be
%divisible by 12 so the counter restarts after a flip.
angles = -179:2:180;
nangles = numel(angles);
rects = nan(nangles, 4);
for k = 1:numel(angles)
     x = center(1) + targetRadius * cos(angles(k)*pi/180);
     y = center(2) + targetRadius * sin(angles(k)*pi/180);
     rects(k,:) = [x-dotRadius, y-dotRadius, x+dotRadius, y+dotRadius];
end
counter = 1;

%Start drawing dots 
while 1  
    
    for k = 1:12
        
       %Clear our stimulusBuffer by creating an all-black background
       Screen('FillRect', stimulusBuffer, bkgColour, [0,0,960,540]);
     
       %Draw circle in a specific location into our stimulusBuffer
       Screen('FillOval', stimulusBuffer, dotColour, rects(counter,:));
       
       %Add the new image to our queue; the queue flips automatically once
       %12 frames have been added
       PsychProPixx('QueueImage', stimulusBuffer);
       
       counter = counter +1;
    end
    
    %If we run out of target locations, loop back to the beginning
    if counter > nangles
        counter = 1;
    end
   
    %Keypress to exit    
    [keyIsDown, ~, ~, ~] = KbCheck;
    if keyIsDown 
        break
    end 
    
end

%Close
Datapixx('SetPropixxDlpSequenceProgram', 0);
Datapixx('RegWrRd');

PsychProPixx('DisableFastDisplayMode', 1);         
Screen('Closeall');

end