resend of Programing and Modeling

[From Bill Williams 22 June 02 10:30 CST ]

Something seems to have gone wrong with my attempt to email the post Programing
and Modeling-- so I'm trying again.

Bill Williams

main }1 (89 Bytes)

Eb2.exe (51.3 KB)

Eg.exe (51.3 KB)

Bias2.exe (51.4 KB)

···

______________________________________________________________________
Do you want a free e-mail for life ? Get it at http://www.email.ro/

Recently while trying write a program that would illustrate how a disturbance
would be transmitted in a ring of linked control loops, I encountered an
effect which I had not anticipated. When a pulsed disturbance was applied at
one point of the ring, the disturbance appeared to organize itself and then
travel around the ring. But, it proceeded in only one direction. Since I had
thought that the ring was constructed symetrically I was puzzled as to how
this could happen.

Eventually I recognized that I had made a mistake in applying the disturbance
the ring and effectively at the same time added up the effects of the
distubance. What I didn't realize was that applying the disturbance and
adding up the effects within one loop was changing the values for the
controlled variable while the disturbance was being applied. What I should
have been doing was first apply the disturbance for the whole ring, and then
in a second loop add up the effects. The follow fragment of code contains the
mistake. Most of the code consists of intregral control loops connecting the
controlled variables, X and Y coordinates, first to the left around the ring
and then to the right.

{ program fragment : see EB.PAS for full source }

for i := 1 to first_ring do
   begin

    if i = 1 then d := first_ring else d := i - 1;

               error := Ax[i] - Ax[d];
              leftx := error * g2;
              oleftx[i] := oleftx[i] / s2 + leftx;

              error := Ay[i] - Ay[d];
              lefty := error * g2;
              olefty[i] := olefty[i] / s2 + lefty;

    if i = first_ring then d := 1 else d := i + 1;

              error := Ax[i] - Ax[d];
              rightx := error * g2;
              orightx[i] := orightx[i] / s2 + rightx;

              error := Ay[i] - Ay[d];
              righty := error * g2;
              orighty[i] := orighty[i] / s2 + righty;

(* the following two lines are misplaced ! *)

    Ax[i] := + orightx[i] + oleftx[i] ;
    Ay[i] := + orighty[i] + olefty[i] ;
end;

(* This is where changes should be added up-- after the effect of the
  disturbance has been applied to all the controlled variables in the ring *)

for i := 1 to first_ring do
  begin
    Ax[i] := + orightx[i] + oleftx[i] ;
    Ay[i] := + orighty[i] + olefty[i] ;
  end;
  *)

The effect of the mistake can be seen in the very different behaivor of two
demos "EB.EXE" and "EG.EXE". The controlled variables in "EB.EXE" ( the
bad example ) are distorted. And, when a disturbance is applied to the ring
the result is a pulse train travelling one way around the ring. It was only
I encountered this unexpected result that I recognized the mistake I had
made by not separating applying the disturbance to the ring from adding up
the effect of the disturbance.

To recreate the effect of a pulse travelling around the ring in one direction
I modified the corrected version by changing the gain by reducing it by
half in one direction and increasing it by half in the other. This created
some additional, and again, unanticipated but interesting side effects.
( Easier to view than describe or explain. )

The display could be improved by changing the coordinates from rectangular to
a polar orrientation. But, I've managed to do this on some newer programs,
but haven't yet and probably won't get around to doing so on this routine
in the near future. My having been able to get the present ring running at
all is due altogether to my having borrowed code from Bill Power's version
of an earlier ring program. And, I'm not sure if it is possible to translate
an XY scheme into polar coordinates without introducing distortions.

The effect of my mistake had me puzzled for more time than I'd like to admitt.

Investigating the effect of a disturbance upon a ring would be conceptually
simpler if one connected up op-amps in a ring. Then one wouldn't have to
think about how to treat continuous time in a sequential digital program.
But, it would take a big, expensive circuit board.

Files: "TEXT", "EB.PAS" (source), "EB.EXE", "EG.EXE" contrasting examples
bad and good ( or at least better ) and BIAS.EXE in which the gain of the
left and right connections between the controlled variables is shifted by
reducing one direction by half and increasing the other direction by 1.5.

When running EB.EXE it will speed things up by stablizing the ring if one
first enters an uppercase "S" to smooth out the ring's jitter, and then
restores the sensitivity of the ring by entering a lowercase "s".

As next to final note, correcting the code had a further unexpected effect
of making a big change in the stablity of the ring. I had to change the
integrating values to get the "good" ring to have approximately the same
behavior as the misbehaving program. But, I found the misbehaving program
interesting.

The next step, I think, in exploring ways in which control loops can be
linked into larger systems will be to construct a rectangular lattice
structure and investigate how it behaves when disturbed.

I'm sure there's a fair amount of "dead code" in the present program.
It was cobbled together from fragments of previous programs rather
than written from scratch.

Am I still missing something in constructing the ring? I'm planning
on using the three "EXE" programs as examples as a part of presentation
in an economics conference to be held here at UMKC in July. The examples are
intended to illustrate the typical sort of activity that goes on when a
non-programer goes about attempting to develop programs to simulation
control processes. This includes lots of time hunting program bugs and
other sorts of mistakes. At least when I attempt to write programs, lots
of mistakes occur. Most of them aren't as interesting as the one explored
here. Comments would be welcome.

Bill Williams

program BAD_Example; { EB.EXE 4 indexed stripped out of i16f.pas 6 June 02 }
  uses dos, crt, graph, grutils;
    var

rightx,righty,leftx,lefty, error, iex, oex, o1ex, o2ex, o3ex : real;

     loey, lo1ey, lo2ey, lo3ey,
     loex, lo1ex, lo2ex, lo3ex,

     iey, oey, o1ey, o2ey, o3ey, Ro1ey, Ro2ey, Ro3ey : real;

      g1,s1,g2,s2,pi,alpha : real;
      i,r,d : integer;
      key : char;
      const first_ring = 60;
   var

exl, ex,Rx,Ax,ix,ox : array[1..first_ring] of real;
eyl, ey,Ry,Ay,iy,oy : array[1..first_ring] of real;

     lex,lRx,lrAx,lix,lox : array[1..first_ring] of real;
     ley,lRy,lrAy,liy,loy : array[1..first_ring] of real;

     Rex,RRx,RrAx,Rix,Rox : array[1..first_ring] of real;
     Rey,RRy,RrAy,Riy,Roy : array[1..first_ring] of real;

          ioex, iix : array[1..first_ring] of real;
          ioey, iiy : array[1..first_ring] of real;

orightx, oleftx, Rioex, Riix : array[1..first_ring] of real;
orighty, olefty, Rioey, Riiy : array[1..first_ring] of real;

   var { graphic variables }
      Cx, Cy : integer;

procedure specify_reference_values;
begin
   for i := 1 to first_ring do { set reference values }
      begin
       alpha := -2.0*pi*(i - 1)/first_ring;
       rx[i] := round(r*(-cos(alpha)));
       ry[i] := round(r*(+sin(alpha)));

       Ax[i] := rx[i];
       Ay[i] := ry[i];

    end;
end; { initialize values for References first_loop }

procedure build_display;
begin
  for i := 1 to first_ring do
   begin
     setcolor(red);
     circle(round(Cx - Ax[i]),round(Cy - Ay[i]),3);

     if i = 1 then
         begin
           setcolor(lightred);
           circle(round(Cx - Ax[i]),round(Cy - Ay[i]),3);
         end;

     setcolor(brown);
     line(round(Cx - Ax[i]),round(Cy - Ay[i]),
          round(Cx - rx[i]), round(Cy - ry[i]));

       setcolor(blue);
       circle(round(Cx - rx[i]),round(Cy - ry[i]),3);

       if i = 1 then
         begin
           setcolor(yellow);
           circle(round(Cx - rx[i]),round(Cy - ry[i]),3);
         end;

   if i = first_ring then d := 1 else d := i + 1;
       setcolor(blue);
      line(round(Cx - Ax[i]),round(Cy - Ay[i]),
           round(Cx - Ax[d]),round(Cy - Ay[d]));

  end;
end; { of build display }

procedure clear_display;
begin
   setcolor(lightgray);
  for i := 1 to first_ring do
   begin
     circle(round(Cx - Ax[i]),round(Cy - Ay[i]),3);
     line(round(Cx - Ax[i]),round(Cy - Ay[i]),
          round(Cx - rx[i]), round(Cy - ry[i]));

   if i = first_ring then d := 1 else d := i + 1;
      line(round(Cx - Ax[i]),round(Cy - Ay[i]),
           round(Cx - Ax[d]),round(Cy - Ay[d]));

  end;
end; { of clear display }

procedure disturbance;
  begin
   if key = 'I' then
     begin
      i := 1;
      Ax[i] := Ax[i] + 100;
      Ay[i] := Ay[i] + 000;
      key := '0';
     end;

     if key = 'i' then
     begin
      i := 31;
      Ax[i] := Ax[i] + 100;
      Ay[i] := Ay[i] + 000;
      key := '0';
     end;

   end;

procedure smooth1;
  begin
   if key = 'S' then
     begin

        g2 := 0.3;

      key := '0'; { reseting key so disturbance will be momentary }
     end;
  end;

procedure smooth2;
  begin
   if key = 's' then
     begin
        g2 := 0.5635;
      key := '0'; { reseting key so disturbance will be momentary }
     end;

   if key = 'I' then
     begin
      i := 31;
      Ax[i] := Ax[i] + 100;
      Ay[i] := Ay[i] + 000;
      key := '0'; { reseting key so disturbance will be momentary }
     end;

end;

   clear_display;
   disturbance;
   smooth1;
   smooth2;

for i := 1 to first_ring do { pulls current first_ring to outer referece }
   begin
       ex[i] := Rx[i] - Ax[i];
       ix[i] := ex[i] * g1;
       ox[i] := ox[i] + ( ix[i] - ox[i])/s1;
       Ax[i] := ox[i];

       ey[i] := Ry[i] - Ay[i];
       iy[i] := ey[i] * g1;
       oy[i] := oy[i] + ( iy[i] - oy[i])/s1;
       Ay[i] := oy[i];

       lrAx[i] := Ax[i];
       lrAy[i] := Ay[i];

  end;

for i := 1 to first_ring do
   begin

    if i = 1 then d := first_ring else d := i - 1; { closes ring }

    error := Ax[i] - Ax[d];
    leftx := error * g2; { "g2" changed in BIAS --> g2 * 1.5 }
    oleftx[i] := oleftx[i] / s2 + leftx; { or change "S2" in BIAS }

    error := Ay[i] - Ay[d];
    lefty := error * g2; { "g2" changed in BIAS --> g2 * 1.5
    olefty[i] := olefty[i] / s2 + lefty; { or change "S2" in BIAS }

    if i = first_ring then d := 1 else d := i + 1; { closes ring }

    error := Ax[i] - Ax[d];
    rightx := error * g2; { "g2" changed in BIAS --> g2 * 1.5 }
    orightx[i] := orightx[i] / s2 + rightx; { or change "S2" in BIAS }

    error := Ay[i] - Ay[d];
    righty := error * g2; { "g2" changed in BIAS --> g2 * 1.5
    orighty[i] := orighty[i] / s2 + righty; { or change "S2" in BIAS }

    Ax[i] := + orightx[i] + oleftx[i] ;
    Ay[i] := + orighty[i] + olefty[i] ;

   end;

(*

This is where changes should be added up.
for i := 1 to first_ring do
  begin
    Ax[i] := + orightx[i] + oleftx[i] ;
    Ay[i] := + orighty[i] + olefty[i] ;
  end;
  *)

  build_display;

  delay(100); { to reduce screen flicker }

  (*
  setcolor(blue);
  circle(round(Cx),round(Cy),140);
  circle(round(Cx),round(Cy),50);
    *)

   if keypressed then key := readkey;

until key in ['q','Q'];
closegraph;
end.