Second discrim stim experiment version

[From Bill Powers (950306.1210 MST)]

Bruce Abbott, Rick Marken, Tom Bourbon, other modelers --

Below is another version of the discriminative stimulus experiment, built
on Bruce Abbott's program SDTEST1. This is SDTEST2p. The final letter
indicates it is Powers' version, in case someone else is working on an
SDTEST2.

Here the cursor is always moved horizontally by a horizontal movement of
the mouse. Above and below the cursor line are two target lines, a red one
and a green one, which move independently. At random intervals red and
green are interchanged. The minimum interval between switches is 200/60
sec, and the maximum is 500/60 sec. When the upper target is red, the
accumulating error is increased by the tracking error relative to the upper
target; when the lower target is red, the same error is affected by the
tracking error relative to the lower target.

In the middle of the cursor a number is shown, indicating the absolute
average error between the cursor position and whichever target is red. The
object is to keep the number as small as possible.

This is analogous to the operant conditioning experiment in which the same
behavior is switched between two keys in order to maintain reinforcement at
the desired rate. A discriminative stimulus indicates which key is active.
We could construct a parallel to the case in which the two keys operate
under different schedules by changing the ratio of handle movement to
cursor movement when we switch the effective target.

The "stimulus generalization" phenomenon might be seen if we were to
periodically make both targets red for a few seconds. This would create a
conflict between the reference settings for which target is to be tracked.
One possible outcome is that the cursor will be moved to a position midway
between the targets (or some proportion of the distance). Another is that
the cursor will freeze. Still another is that the cursor will oscillate
between the targets. This would have to be done at a moment when the two
targets are close together so they can both be seen in the center of vision
at the same time.

It should be noted that Bruce's version, SDTEST1, is analogous to the case
where two different behaviors are involved. I think that one should also be
explored, but that the experiment needs some refinement. When the
controlled variable itself gives an immediate indication of a change of
conditions, the discriminative stimulus doesn't add much to the ability to
control. What we need is an indirectly controlled variable which depends on
the behavior that is in effect, but in such a way that the discriminative
stimulus can materially speed up the changeover between behaviors.

In the present experiment, we can compare the ability to keep the total
error small with and without the discriminative stimulus.

Best,

Bill P.

···

======================================================================
program SDtest2p;

{ Program to investigate the role of the discriminative stimulus. The
  participant's task is to track whichever cursor will keep the score
  shown at the cursor position as close to zero as possible. The
  target to be tracked is shown in red.

  Based on SDtest1 written by B. Abbott (950305)

}

uses
  CRT, DOS, Graph, GrUtils, Mouse;

const
  MAXDATA = 3600;

type
  datalist = array[1..MAXDATA] of integer;
  dataptr = ^datalist;

var
  h, d1,d2, state: dataptr;
  MaxX, MaxY, c, olddt, olddb, Oldc, CursColor, x, y, SD: integer;
  error: real;
  slow: real;
  ch: char;

procedure InitHeapVars;
begin
  new(h);
  new(state);
  new(d1);
  new(d2);
end;

procedure DisposeHeapVars;
begin
  dispose(d2);
  dispose(d1);
  dispose(state);
  dispose(h);
end;

procedure InitScreen;
begin
  ClrScr;
  InitGraphics;
  MaxX := GetMaxX; MaxY := GetMaxY;
  outtextXY(240, 20, 'PRACTICE TIME');
  SetColor(yellow);
  outtextXY(10, 60, 'Press the SPACE BAR to change the target color.');
  SetColor(cyan);
  outtextXY(10, 80,
  'Use the mouse to move the white cursor to track the red target');
  outtextXY(10, MaxY - 120,
  'Press the ESCape key to begin...');
  SetWriteMode(XORPUT);
end;

procedure InitParams;
begin
  Slow := 0.005;
  SD := 1;
  olddt := 0;
  olddb := 0;
  oldc := 0;
  error := 0;
end;

procedure InitDist(dist: dataptr);
var
  i: integer;
  d1, d2, d3, avg, max, tmp : real;
begin
  d1 := 0.0; d2 := 0.0; d3 := 0.0;
  for i := 1 to MAXDATA do
    begin
      d1 := random * 10000.0 - 5000.0;
      d2 := d2 + slow*(d1 - d2);
      d3 := d3 + slow*(d2 - d3);
      dist^[i] := round(d3);
  end;
  avg := 0.0;
  for i := 1 to MAXDATA do avg := avg + dist^[i];
  avg := avg/MAXDATA;
  for i := 1 to MAXDATA do dist^[i] := dist^[i] - round(avg);
  max := 0;
  for i := 1 to MAXDATA do if abs(dist^[i]) > max then max :=
abs(dist^[i]);
  for i := 1 to MAXDATA do { normalize to max of 120 }
   begin
    tmp := 120.0/max;
    dist^[i] := round(dist^[i]*tmp);
   end;
end;

procedure DrawCursor(c: integer);
begin
  SetColor(BLACK);
  line(oldc, maxy div 2 - 20, oldc, maxy div 2 + 20);
  oldc := c + maxx div 2;
  SetColor(WHITE);
  line(oldc, maxy div 2 - 20, oldc, maxy div 2 + 20);
end;

procedure DrawTarget(dt, db, SD: integer);
begin

  SetColor(BLACK);
  line(olddt, maxy div 2 + 20, olddt, maxy div 2 + 35);
  olddt := dt + maxx div 2;
  if SD = 2 then setcolor(lightgreen) else setcolor(lightred);
  line(olddt, maxy div 2 + 20, olddt, maxy div 2 + 35);
  SetColor(BLACK);
  line(olddb, maxy div 2 - 20, olddb, maxy div 2 - 35);
  olddb := db + maxx div 2;
  if SD = 1 then setcolor(lightgreen) else setcolor(lightred);
  line(olddb, maxy div 2 - 20, olddb, maxy div 2 - 35);
end;

procedure Beep;
begin
  sound(2000);
  delay(50);
  nosound;
end;

procedure Practice;
var handle, cursor,d: integer;
begin
  readmouse;
  x := mousex;
  y := mousey;
  drawcursor(handle + d1^[121]);
  repeat
    readmouse;
    handle := mousex div 4;
    retrace;
    cursor := handle;
    drawcursor(cursor);
    DrawTarget(d1^[121],d2^[121],SD);
    if keypressed then
      begin
        ch := readkey;
        if ch = ' ' then
            if(SD = 2) then SD := 1 else SD := 2;
      end;
  until ch = #27;
  beep;
end;

procedure RunExpt;
var i, j, handle, cursor,
  count, switchcount,d: integer;
  numstr: string;
begin
  setViewPort(0, 0, MaxX, MaxY div 3, clipoff);
  ClearViewPort;
  setViewPort(0, MaxY - 130, MaxX, MaxY, clipoff);
  ClearViewPort;
  SetViewPort(0, 0, MaxX, MaxY, clipoff);
  count := 0;
  error := 0.0;
  randomize;
  SD := 1;
  setfillstyle(0,0);
  switchcount := random(300)+120;
  for j := -120 to MAXDATA-1 do { 2-sec run-in period }
    begin
      i := abs(j) + 1;
      readmouse;
      handle := mousex div 4;
      retrace;
      cursor := handle;
      h^[i] := handle;
      state^[i] := SD;
      drawcursor(cursor);
      if SD = 1 then error := error + abs(d1^[i] - handle)
      else error := error + abs(d2^[i] - handle);
      error := error * 0.98;
      str(error/10.0:6:0,numstr);
      bar(maxx div 2 - 42 + cursor,maxy div 2 - 5,
          maxx div 2 + 42 + cursor, maxy div 2 + 5);
      outtextxy(maxx div 2 - 40 + cursor,maxy div 2 - 5,numstr);
      DrawTarget(d1^[i],d2^[i],SD);
      if (count >= switchcount) then
      begin
        count := 0;
        if SD = 1 then SD := 2 else SD := 1;
        switchcount := random(300)+120;
      end;
      inc(count);
    end;
end;

begin
  InitScreen;
  InitHeapVars;
  InitParams;
  InitDist(d1);
  InitDist(d2);
  setwritemode(COPYPUT);
  DrawTarget(1,d1^[121],d2^[121]);
  Practice;
  RunExpt;
  RestoreCRTMode;
  DisposeHeapVars;
  CloseGraph;
end.