Blind tracking using Hans' system model

[From Bill Powers (950509.1510 MDT)]

I have modified my "blind tracking" program so that the "system" part behaves
according to the same equations that governs Hans' system model. Now we can
compare a human being's performance in controlling that kind of system with
the performance of the predictive/adaptive program.

I have changed the values of the constants a, b, and c to give a reasonable
effect on the screen (particularly slowing the system model so it does not
come instantly to its final state). I have adjusted the scaling so that the
handle movement is the same size, on the average, as the cursor movement on
the screen.

I find it very difficult to control when the cursor is not visible, even
though there is no disturbance.

Best,

Bill P.

···

=======================================================================
program blindtk1;

{ A target moves in a single cycle of a slow sine-wave pattern.
The participant makes a cursor follow the target. There are two
modes of running: with a visible or an invisible cursor.
The object is to see how a person tracks the target during periods
when the cursor can't be seen, and how much improvement there can
be with practice.

(950509)
Modified by WTP to use "system" model of Hans Blom between handle and
cursor position. Scaling adjusted to maintain 1:1 effect of handle
on cursor.

}

uses dos,crt,graph,grutils,mouse;

const maxdata = 900;

type dataarraytype = array[0..maxdata-1] of integer;

var cursx,targx: dataarraytype;
    targetx,targety,oldtx,oldty: integer;
    MaxX, MaxY, Xcenter, Ycenter: integer;
    index,oldmx,oldmy: integer;
    ct,bt,at,cursor,u: real;
    Time,Scale: real;
    ch: char;
    visible: boolean;

procedure InitScreen;
begin
  ClrScr;
  InitGraphics;
  MaxX := GetMaxX; MaxY := GetMaxY;
  Xcenter := (MaxX+1) div 2;
  Ycenter := (MaxY+1) div 2;
  OutTextXY(20, MaxY-50, 'Press ESC to Quit...');
end;

procedure InitSystem;
begin
targetx := 0; targety := 0;
mousex := 0; mousey := 0;
  ct := 1.0/20.0;
  at := 0.98/20.0;
  bt := 0.1/20.0;
end;

procedure showtarget(init: boolean);
var t: real;
begin
if(not init) then
rectangle(xcenter + oldtx - 2,ycenter - oldty - 2,
           xcenter + oldtx + 2, ycenter - oldty + 2);

oldtx := targetx; oldty := targety;

rectangle(xcenter + oldtx - 2,ycenter - oldty - 2,
           xcenter + oldtx + 2, ycenter - oldty + 2);
end;

procedure showcursor(init: boolean);
var x,y,i,j: integer;
begin
if(not init) then
rectangle(xcenter + oldmx - 8,ycenter - oldmy - 8,
           xcenter + oldmx + 8, ycenter - oldmy + 8);
oldmx := round(cursor); oldmy := round(mousey);
rectangle(xcenter + oldmx - 8,ycenter - oldmy - 8,
           xcenter + oldmx + 8, ycenter - oldmy + 8);
end;

procedure calibrate; {this procedure called }
var c1,c2: real; {only if no calibration exists}
begin
clearviewport;
mousex := 0;
outtextxy(0,10,'Set Mouse to 0 on ruler, press space bar');
  while not keypressed do readmouse;
c1 := mousex;
ch := readkey;
outtextxy(0,30,'Slide Mouse to 6 inches on ruler, press space bar');
while not keypressed do readmouse;
c2 := mousex;
ch := readkey;
scale := round(1.333333*xcenter)/(c2 - c1);
clearviewport;
end;

function calmouse: boolean;
var cf: file of real;
begin
assign(cf,'mousecal');
{$i-}
reset(cf);
{$i+}
if IOresult = 0 then begin read(cf,scale); close(cf); end
else
  begin
   rewrite(cf);
   calibrate;
   write(cf,scale);
   close(cf);
  end;
end;

begin
InitSystem;
{ InitMouse;} {Note: do not initialize when running inside TP 7.0}
clrscr;
gotoxy(1,15);
writeln('Press v for visible cursor, i for invisible');
ch := readkey;
if ch in ['v','V'] then visible := true else visible := false;
InitScreen;
calmouse; { calibrate mouse if necessary}
InitSystem;
clearviewport;
setwritemode(XorPut);
outtextxy(0,20,
'Center large square on small square, then cursor on pad, strike space
bar');
ShowTarget(true);
ShowCursor(true);
mousey := 0;
repeat
  retrace;
  readmouse;
  mousey := 0;
  ShowCursor(false);
until keypressed;
ch := readkey;
clearviewport;
if visible then
  begin
   ShowTarget(true);
   ShowCursor(true);
  end;
time := 0.0;
index := 0; cursor := 0.0;
while (time < 900.0) and (not keypressed) do
  begin
   retrace;
   readmouse;
   mousey := 0;
   targetx :=round(2*xcenter div 3 * sin(2*pi* time/900.0));
   ShowTarget(false);
   u := scale*mousex/5.0;
   cursor := 20.0*(ct + at*cursor + bt*u);
   cursx[index] := round(cursor);
   targx[index] := targetx;
   if visible then ShowCursor(false);
   time := time + 1.0;
   inc(index);
  end;
  ch := readkey;
  clearviewport;
  setcolor(lightred);
  outtextxy(0,20,'TARGET POSITION');
  setcolor(white);
  outtextxy(0,40,'CURSOR POSITION');
  for index := 0 to 899 do
  begin
   putpixel(2*index div 3, ycenter - cursx[index],white);
   putpixel(2*index div 3, ycenter - targx[index],lightred);
   putpixel(2*index div 3, ycenter,lightgray);
  end;
  while keypressed do ch := readkey;
  ch := readkey;
  restorecrtmode;
  closegraph;
end.