Created
January 8, 2015 22:26
-
-
Save dxjones/75640b579b003e42f30b to your computer and use it in GitHub Desktop.
Demo_FlipBug.m
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| % Demo_FlipBug.m | |
| % | |
| % 2015-01-08 [email protected] | |
| % | |
| % set ShowBug to false to avoid missed Flips | |
| % set ShowBug to true to demonstrate missed Flips | |
| ShowBug = true; % see line #75 | |
| try | |
| Priority(9); | |
| w = Screen('OpenWindow', 0); | |
| FlipInterval = Screen('GetFlipInterval', w); | |
| winfo = Screen('GetWindowInfo', w); | |
| vblank = winfo.VBLStartline; | |
| vtotal = winfo.VBLEndline; | |
| % - - - - - | |
| r = Screen('Rect', 0); | |
| ScreenHeight = RectHeight(r); | |
| ScreenWidth = RectWidth(r); | |
| cx = ScreenWidth/2; | |
| cy = ScreenHeight/2; | |
| zx = cx - (vtotal/2); | |
| zy = cy - (vtotal-vblank)/2; | |
| radius = 0.45 * min(ScreenHeight, ScreenWidth); | |
| x0 = (ScreenWidth/2) - (vtotal/2); | |
| x1 = x0 + vtotal; | |
| x_vblank = x0 + (x1-x0) * (vblank/vtotal); | |
| y0 = 0.10 * ScreenHeight; | |
| y1 = y0 + 0.80 * ScreenHeight; | |
| y_vblank = y1 - (y1-y0) * (1/1.5); | |
| % - - - - - | |
| N = 1 + vtotal; | |
| beam = false(N,1); | |
| vt = zeros(N,1); | |
| m = zeros(N,1); | |
| bp = zeros(N,1); | |
| t_pre = zeros(N,1); | |
| t_post = zeros(N,1); | |
| t_mid = zeros(N,1); | |
| vt_pre = zeros(N,1); | |
| vt_post = zeros(N,1); | |
| vt_mid = zeros(N,1); | |
| % main loop includes random delays to get a variety of beam positions | |
| % "beamcount" controls how many different beam positions we need | |
| % Caution: main loop will become very slow if beamcount > 0.95 * vtotal | |
| beamcount = 0.95 * vtotal; | |
| VBL_timestamp = 0; | |
| while true | |
| if nnz(beam) >= beamcount | |
| break | |
| end | |
| if KbCheck | |
| break | |
| end | |
| % simple animation shows progress through loop | |
| y = nnz(beam); | |
| Screen('DrawLine', w, 0, 100,y, 400,y); | |
| % wait a random delay | |
| delay = rand * FlipInterval; | |
| WaitSecs(delay); | |
| if ShowBug | |
| WaitSecs(2*FlipInterval); | |
| end | |
| % wait for a beampos we haven't seen before | |
| while true | |
| t0 = GetSecs; | |
| beampos = Screen('GetWindowInfo', w, 1); | |
| t1 = GetSecs; | |
| b = 1 + beampos; | |
| if ~beam(b) | |
| beam(b) = true; | |
| break | |
| end | |
| break | |
| end | |
| % Flip | |
| when = 0; | |
| % when = GetSecs + 0.010; | |
| [VBL_timestamp Stim_timestamp Flip_timestamp Missed Beampos_after_Flip ] = Screen('Flip', w, when,1); | |
| % Calculate Flip Time | |
| % (normally, this would be done before the Flip) | |
| t_pre(b) = t0; | |
| t_post(b) = t1; | |
| t_mid(b) = (t0 + t1) / 2; | |
| vt_pre(b) = CalculateFlipTime(t_pre(b), beampos, vblank, vtotal, FlipInterval); | |
| vt_post(b) = CalculateFlipTime(t_post(b), beampos, vblank, vtotal, FlipInterval); | |
| vt_mid(b) = CalculateFlipTime(t_mid(b), beampos, vblank, vtotal, FlipInterval); | |
| FlipDelta = VBL_timestamp - vt_mid(b); | |
| % record actual VBL, etc. | |
| vt(b) = VBL_timestamp; | |
| m(b) = Missed; | |
| bp(b) = Beampos_after_Flip; | |
| % - - - - - | |
| px = x0 + (x1-x0) * (b/vtotal); | |
| py = y1 - (y1-y0) * ((Beampos_after_Flip - vblank) / (1.5*(vtotal - vblank))); | |
| Screen('DrawLine', w, 128, x0,y0, x0,y1); | |
| Screen('DrawLine', w, 128, x1,y0, x1,y1); | |
| Screen('DrawLine', w, 128, x0,y0, x1,y0); | |
| Screen('DrawLine', w, 128, x0,y1, x1,y1); | |
| Screen('DrawLine', w, 128, x_vblank,y0, x_vblank,y1); | |
| Screen('DrawLine', w, 128, x0,y_vblank, x1,y_vblank); | |
| if FlipDelta < (FlipInterval/2) | |
| color = [0 255 0 255]; | |
| else | |
| color = [255 0 0 255]; | |
| Screen('FillRect', w, color, [px-1 y1+10 px+1 y1+110]); | |
| end | |
| Screen('FillRect', w, color, [px-1 py-3 px+1 py+3]); | |
| % - - - - - | |
| end | |
| % hocus-pocus to make sure we close all windows | |
| wlist = Screen('Windows'); | |
| Screen('CloseAll'); | |
| Priority(0); | |
| catch e | |
| CatchGraphicsError(e, 'BeginGraphics'); | |
| % hocus-pocus to make sure we close all windows | |
| wlist = Screen('Windows'); | |
| Screen('CloseAll'); | |
| Priority(0); | |
| end | |
| scanline = 0:vtotal; | |
| scanlines_per_msec = (vtotal+1) / (1000 * FlipInterval); | |
| % guess at beampos deadline for successful flips | |
| vdeadline = 0.75 * vblank; | |
| %% | |
| % Figure 1 shows Beampos before/after Flip | |
| % | |
| % Notice Beampos after Flip is almost always ... | |
| % between vblank and vtotal, occasionally wraps around | |
| % | |
| % adjust returned beampos to wrap around past the end of vtotal | |
| X = bp < (vtotal/2); | |
| bp( X ) = bp( X ) + (1+vtotal); | |
| figure(1); | |
| plot(vtotal*[0 1],[0 0],'k:', ... | |
| vtotal*[0 1], vblank*[1 1],'k:',... | |
| vtotal*[0 1], vtotal*[1 1],'k:', ... | |
| [0 0], vtotal*[0 1],'k:', ... | |
| vdeadline*[1 1],vtotal*[0 1],'g:', ... | |
| vblank*[1 1], vtotal*[0 1], 'k:', ... | |
| vtotal*[1 1], vtotal*[0 1], 'k:', ... | |
| scanline(beam),bp(beam),'r.'); | |
| % vblank - scanlines_per_msec*[1 1], vtotal*[-1 2],'r:', ... | |
| % vblank - scanlines_per_msec*[2 2], vtotal*[-1 2],'r:', ... | |
| % vblank - scanlines_per_msec*[3 3], vtotal*[-1 2],'r:', ... | |
| % vblank - scanlines_per_msec*[4 4], vtotal*[-1 2],'r:', ... | |
| % vblank - scanlines_per_msec*[5 5], vtotal*[-1 2],'r:', ... | |
| % vblank - scanlines_per_msec*[6 6], vtotal*[-1 2],'r:', ... | |
| % vblank - scanlines_per_msec*[7 7], vtotal*[-1 2],'r:', ... | |
| xlabel('Beampos before Flip'); | |
| ylabel('Beampos after Flip'); | |
| text(vtotal/2, vblank, 'VBLANK'); | |
| text(vtotal/2, vtotal, 'VTOTAL'); | |
| axis([0 vtotal vblank-10 vtotal+10]); | |
| axis square | |
| %% | |
| % Figure 2 shows accuracy of Calculated Flip Time | |
| % | |
| % Notice blue data points are very close to zero | |
| delta_pre = vt - vt_pre; | |
| delta_post = vt - vt_post; | |
| delta_mid = vt - vt_mid; | |
| figure(2); | |
| plot(vtotal*[0 1],[0 0],'k:', ... | |
| vtotal*[0 1],1000*FlipInterval*[1 1],'k:', ... | |
| vtotal*[0 1],(vtotal+1)*[1 1],'k:', ... | |
| vdeadline*[1 1],1000*FlipInterval*[-1 2],'g:', ... | |
| vblank*[1 1],1000*FlipInterval*[-1 2],'k:', ... | |
| vtotal*[1 1],1000*FlipInterval*[-1 2],'k:', ... | |
| scanline(beam),1000*delta_pre(beam),'g.', ... | |
| scanline(beam),1000*delta_mid(beam),'b.', ... | |
| scanline(beam),1000*delta_post(beam),'r.'); | |
| figure(2), axis([0 vtotal -0.2 0.2]); | |
| xlabel('Beampos before Flip'); | |
| ylabel('Flip Time Prediction Error (msec)'); | |
| title('Flip Time Prediction Error ... +ve means actual Flip occured later'); | |
| %% | |
| % Figure 3 highlights missed Flips | |
| figure(3); | |
| plot(vtotal*[0 1],[0 0],'k:', ... | |
| vtotal*[0 1],1000*FlipInterval*[1 1],'k:', ... | |
| vtotal*[0 1],(vtotal+1)*[1 1],'k:', ... | |
| vdeadline*[1 1],1000*FlipInterval*[-1 2],'g:', ... | |
| vblank*[1 1],1000*FlipInterval*[-1 2],'k:', ... | |
| vtotal*[1 1],1000*FlipInterval*[-1 2],'k:', ... | |
| scanline(beam),1000*delta_pre(beam),'g.', ... | |
| scanline(beam),1000*delta_mid(beam),'b.', ... | |
| scanline(beam),1000*delta_post(beam),'r.'); | |
| figure(3), axis([0 vtotal 1000*FlipInterval-0.2 1000*FlipInterval+0.2]); | |
| xlabel('Beampos before Flip'); | |
| ylabel('Flip Time Prediction Error (msec)'); | |
| title('Flip Time Prediction Error ... (Missed Flips) ... +ve means actual Flip occured later'); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment