[From Bill Powers (950306.0930 MST)]
Bruce Abbott (direct post, 950305) --
Bruce sent me the program for a task in which the participant keeps a
vertical cursor line between two stationary target lines above and below
it. When the target lines are red, the horizontal motion of the mouse
affects the horizontal position of the cursor; when the target lines are
green, the vertical motion of the mouse affects the cursor's horizontal
position. Here are some comments for Bruce and other programmers on what
I've learned so far. "SD" means "discriminative stimulus", meaning the
greenness or redness of the target lines. Bruce's program, with some small
adjustments, is reproduced below.
As it stands, the SD is not totally necessary; I'm picking up the switch as
much from tracking error as from the color change. I'm still not very good
at it, but it may be worth taking some data and seeing what it looks like.
Is it usually the case that an SD is redundant with some other indication
that the situation has changed? The basic indication, of course, would be
that the controlled variable is no longer controlled: the cursor starts
departing from the target. On low-ratio operant conditioning schedules,
this would take some time to discover, so the SD could serve as an advance
indication that the controlled variable has (although not visibly) departed
from, or is further from, its reference level. The appropriate perception
to control would then be some combination of the basic controlled variable
and the SD.
I suggest trying another task. Suppose the two halves of the target were
independently disturbed. The task is to track the half that is red. Above
the position of the tracking area, a score is shown which is a leaky
cumulative total of the error (average of the error on whichever tracking
task is active). Since there is no change in the relation of the handle to
the cursor to signal a change in conditions, the person (with no SD
present) would have to notice the increasing score and switch to tracking
the other target. So now the SD would be the only immediate signal that the
situation has changed. The person would learn to start tracking the other
target before the score had changed appreciably.
This comes closer to being a two-level tracking task. Without an SD, the
person would have to discover that the score has started increasing.
Starting with minimal instructions, the person would also have to discover
that the score could be decreased by switching to tracking the other
target. This could be done, but the control would be better if the person
could do the switch as soon as possible after the effective task changed.
Even with the SD, the person would have to discover that the change of
color was a useful sign that tracking should change to the other target.
This suggests an even more realistic experiment, in which there are a
number of potential SDs, all changing from time to time, with only one of
them actually corresponding to a change in conditions. But let's build up
to that one step at a time.
Any further suggestions or alternatives?
Best,
Bill P.
···
=====================================================================
program SDtest1;
{ Program to investigate the role of the discriminative stimulus. The
participant's task is to keep a white cursor (vertical line) aligned
between two vertical lines (target position). When the target is
green, this can be accomplished by moving the mouse horizontally.
When the target is red, this can be accomplished by moving the mouse
vertically. The target color changes at random times throughout
the procedure.
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, d, state: dataptr;
MaxX, MaxY, c, Oldc, CursColor, xoffs, yoffs, x, y, SD: integer;
slow: real;
ch: char;
procedure InitHeapVars;
begin
new(h);
new(state);
new(d);
end;
procedure DisposeHeapVars;
begin
dispose(d);
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,
'Try using the mouse to move the white cursor when the target is green');
outtextXY(40, 100, 'and also when the target is red.');
outtextXY(10, MaxY - 120,
'When you have practiced enough, press the ESCape key to begin...');
SetWriteMode(XORPUT);
end;
procedure DrawTarget(SD: integer);
var TColor: integer;
begin
if SD = 1 then TColor := lightgreen else TColor := lightred;
SetColor(TColor);
SetWriteMode(CopyPut);
line(MaxX div 2, MaxY div 2 - 35, MaxX div 2, MaxY div 2 - 20);
line(MaxX div 2, MaxY div 2 + 35, MaxX div 2, MaxY div 2 + 20);
SetWriteMode(XORPut);
end;
procedure InitParams;
begin
Slow := 0.005;
SD := 1;
xoffs := 0; yoffs := 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 + d^[i];
avg := avg/MAXDATA;
for i := 1 to MAXDATA do d^[i] := d^[i] - round(avg);
max := 0;
for i := 1 to MAXDATA do if abs(d^[i]) > max then max := abs(d^[i]);
for i := 1 to MAXDATA do { normalize to max of 120 }
begin
tmp := 120.0/max;
d^[i] := round(d^[i]*tmp);
end;
end;
procedure DrawCursor(c, init: integer);
begin
SetColor(White);
if init = 0 then
line(oldc, maxy div 2 - 20, oldc, maxy div 2 + 20);
oldc := c + maxx div 2;
line(oldc, maxy div 2 - 20, oldc, maxy div 2 + 20);
end;
procedure Beep;
begin
sound(2000);
delay(50);
nosound;
end;
procedure Practice;
var handle, cursor: integer;
begin
readmouse;
x := mousex;
y := mousey;
if SD = 1 then handle := x else handle := y;
drawcursor(handle + d^[121], 1);
repeat
readmouse;
x := mousex - xoffs;
y := mousey - yoffs;
if SD = 1 then handle := x else handle := y;
retrace;
cursor := handle + d^[121];
drawcursor(cursor, 0);
if keypressed then
begin
ch := readkey;
if ch = ' ' then
begin
case SD of
1: begin
SD := 2;
yoffs := mousey - x;
end;
2: begin
SD := 1;
xoffs := mousex - y;
end;
end;
DrawTarget(SD);
end;
end;
until ch = #27;
beep;
end;
procedure RunExpt;
var i, j, handle, cursor,
count, switchcount: integer;
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;
randomize;
SD := 1;
switchcount := random(300)+120;
for j := -120 to MAXDATA-1 do { 2-sec run-in period }
begin
i := abs(j) + 1;
readmouse;
x := mousex div 4 - xoffs;
y := mousey div 4 - yoffs;
if SD = 1 then handle := x else handle := y;
retrace;
cursor := handle + d^[i];
h^[i] := handle;
state^[i] := SD;
drawcursor(cursor, 0);
if (count >= switchcount) then
begin
count := 0;
case SD of
1: begin
SD := 2;
yoffs := mousey div 4 - x;
end;
2: begin
SD := 1;
xoffs := mousex div 4 - y;
end;
end;
DrawTarget(SD);
switchcount := random(300)+120;
beep;
end;
inc(count);
end;
end;
begin
InitScreen;
DrawTarget(1);
InitHeapVars;
InitParams;
InitDist(d);
Practice;
RunExpt;
RestoreCRTMode;
DisposeHeapVars;
CloseGraph;
end.