Theodolite models; new MCT code

[Hans Blom, 970304]

(Bill Powers, 97.03.??)

I would MUCH prefer to stick to a realistic example.

All right. Let's stick to this example but do away with the output
saturation. That can be done by specifying a slowly changing setpoint
as I have done in the code below, and as you suggested as well.

Consider this. While the output is saturated, this is due to a very
large error which cannot be corrected. In the past you have analyzed
this sort of situation for the case of conflict between controllers.
In fact, control is lost, one could say. The loop gain is zero while
the output is saturated. Feedback is thus lost; a disturbance cannot
be corrected. That is why I consider output saturation a different
problem that needs separate consideration.

One of my (still-valid) criticisms of the MCT model is that it is
allowed to generate extremely large output forces; ...

There is no difference, in principle. In the PCT model, however,
there is a "slowing factor" whose effect is that the same large
output will only be reached gradually. Hence large outputs are less
noticeable. But if you give the PCT controller sufficient time, it
will generate similarly large outputs. Please check!

Due to PCT's slowing factor, the effect of saturation may be benign
(in some cases!): the output will build up slowly. But remember that
it will also build _down_ slowly!

I have maintained that the one-iteration error correction claimed
for an MCT model is possible only with unrealistic levels of output.
I think we have settled that question: one-jump error correction is
not possible in a physical system.

This is far from true. In the program below, the setpoint is varied
slowly, and one-jump error correction (of a smaller error!) is fully
possible. The same is true while stabilization occurs and x is to be
kept at the same position. It is only when unrealistic reference
levels are specified that one-jump correction is impossible, and the
reason is output saturation: the controller's output section is
insufficiently powerful to achieve what it is commanded to achieve.

To quote you: I think we have settled the question: one-jump error
correction is entirely possible and quite normal in physical systems.

If you want to put the required "self-knowledge" into your MCT
model, that's OK with me.

I'd rather not do that. It would complicate matters greatly and make
our investigation of the principal differences between PCT and MCT
control far less clear. I think that the code below -- which you may
want to beautify again and give a graphical display (thanks! you make
it look so much nicer!) -- could be my final version. It is small
enough to be understandable and leaves all possibilities for any type
of modification.

However, we can restrict the required output in a different way. One
method is to change the reference signal in a more reasonable way
instead of having it jump instantly from one value to another.

I've done that in the code below. And behold, the behavior of the MCT
controller is almost perfect again. Due to its almost perfect model,
to be sure...

Note that one of the things I want to try next is looking at the
effect of errors of computation. But first we have to see both
models running correctly.

Done that. It's just a simple change, compared to my previous code,
in the specification of the reference level. If you want to, you can
release your prettied-up version of this program to the group. If
there is any interest. I think we have lost most of the audience...

We want the physical model of the theodolite to respond to torques
as realistically as possible, and not for its behavior to depend on
the sampling rate with which the control system works.

My guess is that as long as the output saturation problem does not
occur, the value of dt won't matter too much. Think of it this way:
given a certain dt, the output "power" is given in "chunks" of u*dt.
Especially when the output is maximal (saturated), this "power" may
be large. If the reference is (unanticipatedly!) reached somewhere
_during_ the interval that this maximal output "power" is applied,
there is no way to change the output _during this same interval_.
This may cause an inappropriately large output "power chunk" to be
delivered, which needs to be corrected for again afterwards. Hence
over- and undershoots and oscillatory behavior.

Greetings,

Hans

program MCT_theodolite;

uses
  crt;

var
  J, K, dt, r, x, xold, xpre, xsav, d, u, t: real;
  fo: text;

function make_reference (t: real): real;
  {this function defines the setpoint at time t}
begin
  if t < 2.0 then
    make_reference := 0.0 else {0 for 2 secs}
  if t < 7.0 then
    make_reference := (t - 2.0) / 5.0 else {increase for 5 secs}
    make_reference := 1.0 {1 for last 3 secs}
end;

function true_disturb (t: real): real;
  {this function defines the true disturbance}
begin
  if (t < 3.0) or (t > 6.0) then
    true_disturb := 0.0
  else
    true_disturb := 100.0
end;

function do_observation: real;
{this function generates the x that the controller will observe}
begin
  do_observation := 2.0 * x - xold + u/K + true_disturb(t)/K
end;

{initialization}
begin
  clrscr; {clear screen}
  assign (fo, 'output.csg');
  rewrite (fo); {open file for output}
  J := 1.0; {or whatever value...}
  dt := 0.01; {or whatever value...}
  K := (J / dt) / dt; {auxiliary constant}
  t := 0.0; {start at zero time}
  xold := 0.0; {start at zero position}
  x := xold; {and at zero velocity}
  d := 0.0; {assume no disturbance initially}

repeat
{the control loop starts here}
  r := make_reference (t+dt); {define reference}
  u := K * (r - 2.0 * x + xold) - d; {compute output}
  if u < -750.0 then u := -750.0 else {limit output, if desired}
    if u > +750.0 then u := +750.0;
  xpre := 2.0 * x - xold + u / K + d / K; {generate prediction}
  xsav := x; {save present x}
  x := do_observation; t := t + dt; {observe x}
  xold := xsav; {xold := previous x}
  d := d + K * (x - xpre); {estimate disturbance}

{output to screen and file:
time, reference, predicted x, true x, estimated disturbance, output}

  writeln (t:10:3, r:10:3, xpre:10:3, x:10:3, d:10:3, u:10:3);
  writeln (fo, t:10:3, r:10:3, xpre:10:3, x:10:3, d:10:3, u:10:3);

  until t >= 9.0; {at this point the loop ends}
  close (fo)
end.

[From Bill Powers (970304.0941 MST)]

Hans Blom, 970304] --

OK, we seem to have caught up with the weekend posts.

I would MUCH prefer to stick to a realistic example.

All right. Let's stick to this example but do away with the output
saturation. That can be done by specifying a slowly changing setpoint
as I have done in the code below, and as you suggested as well.

All real systems have maximum possible outputs. In fact, in our example, I
have chosen a most unrealistic maximum output of 750 newton-meters, and was
about to suggest reducing it. A barely realistic value (for a theodolite
with a moment of inertia of 1 n-m^2) might be 100 n-m, which would require a
motor and gear train with a stall torque of about 74 foot-pounds, large
enough to move the theodolite through one radian (57 degrees) in 0.2 sec
(including acceleration and deceleration). This assumes no contribution from
the moment of inertia of the motor armature. So I am going to reduce the
limit of output to 100 n-m.

Consider this. While the output is saturated, this is due to a very
large error which cannot be corrected. In the past you have analyzed
this sort of situation for the case of conflict between controllers.
In fact, control is lost, one could say. The loop gain is zero while
the output is saturated. Feedback is thus lost; a disturbance cannot
be corrected. That is why I consider output saturation a different
problem that needs separate consideration.

We can consider it now, by setting a limit to output (as above) which is not
reached when the reference signal slope is low. In the appended program
(adapted from the one you sent me), the PCT and MCT models are compared on
the same screen; by pressing + or - (shifted or unshifted) you can increase
and decrease the slope of the rise in the reference signal, and see where
and how the presence of the limit affects both models. You can switch back
and forth between the models using 'p' for PCT and 'm' for MCT, adjusting
the slope for each one independently.

One of my (still-valid) criticisms of the MCT model is that it is
allowed to generate extremely large output forces; ...

There is no difference, in principle. In the PCT model, however,
there is a "slowing factor" whose effect is that the same large
output will only be reached gradually. Hence large outputs are less
noticeable. But if you give the PCT controller sufficient time, it
will generate similarly large outputs. Please check!

See the appended program. There is no slowing factor in either level of the
PCT model, because the integrations in the environment take care of
stability. The PCT model and the MCT model contain exactly the same limit to
output, 100 n-m. When the slope of the rise of the reference signal is large
enough, both models reach the output limit. However, the PCT model can
tolerate a much larger slope than the MCT model (as presently written) in
the presence of saturation. For those who are not running these programs,
the MCT model hits the limit seriously enough to cause oscillations at a
slope of about 1.5 radians per second (0.67 seconds to slew the theodolite 1
radian or 57 degrees). The PCT model hits the same limit at about the same
slope, but has no oscillation problems until the slope reaches 5 radians per
second (0.2 sec to move 57 degrees).

Due to PCT's slowing factor, the effect of saturation may be benign
(in some cases!): the output will build up slowly. But remember that
it will also build _down_ slowly!

The PCT model responds symmetrically. As I said, there is no slowing factor
in either level of this PCT model.

I have maintained that the one-iteration error correction claimed
for an MCT model is possible only with unrealistic levels of output.
I think we have settled that question: one-jump error correction is
not possible in a physical system.

This is far from true. In the program below, the setpoint is varied
slowly, and one-jump error correction (of a smaller error!) is fully
possible.

I was referring to correcting large errors in one jump.

The same is true while stabilization occurs and x is to be
kept at the same position. It is only when unrealistic reference
levels are specified that one-jump correction is impossible, and the
reason is output saturation: the controller's output section is
insufficiently powerful to achieve what it is commanded to achieve.

I think we are now dealing with a realistic model (although the disturbance
we are using is still extremely large). You seem to be changing your tune,
now that we are dealing with a real situation. Previously, you did not
hetitate to advocate that I see how my model behaves with a step-change in
reference level. Well, we can now see that it behaves very well.

To quote you: I think we have settled the question: one-jump error
correction is entirely possible and quite normal in physical systems.

Nonsense. Physical systems can't change from one state to another instantly.

If you want to put the required "self-knowledge" into your MCT
model, that's OK with me.

I'd rather not do that. It would complicate matters greatly and make
our investigation of the principal differences between PCT and MCT
control far less clear.

If complication is what it takes for the MCT model to work as claimed,
that's what it takes. Complexity IS one of the principal differences between
the PCT and MCT models. I haven't even STARTED to go into how complex your
model really is -- that can wait. If you're willing to concede that the MCT
model behaves less well than the PCT model in the present demonstration,
without any changes, then fine -- we can move on to the next step. But if
you want to upgrade the MCT model to match or exceed the PCT model's
performance, now is the time to do it.

I think that the code below -- which you may
want to beautify again and give a graphical display (thanks! you make
it look so much nicer!) -- could be my final version. It is small
enough to be understandable and leaves all possibilities for any type
of modification.

If you want to, you can
release your prettied-up version of this program to the group. If
there is any interest. I think we have lost most of the audience...

Oh, I think there are people following this discussion with interest, even
if they don't follow the programming details. I will post the appended
source code, instructions, and a runnable (PC) version of the program on my
FTP page, at ftp.frontier.net/users/powers_w.

Best,

Bill P.

ยทยทยท

=============================================================
program theo4mct;
{
This program compares the performance of the MCT and PCT models. Both
models are controlling the position of a theodolite, under the
following conditions:

change of position: 1 radian.
time resolution: 0.01 sec (dt).
Maximum available output torque: 100 newton-meters
Moment of inertia of theodolite: 1 newton-meter^2
Rate of change of reference signal: variable from keyboard
disturbance: 100 n-m, 3 sec duration, random starting time.

The MCT model runs first, in the lower half of the screen. The slope
of the change in reference signal can be adjusted up and down (by
factors of 1.5) by pressing the + and - keys, shifted or unshifted. A
new run is done every time any key is pressed -- except 'p' or 'q'.

Pressing the 'q' key exits the program at any time. Pressing the 'p'
key switches to running the PCT model; after the first time, pressing
'p' or 'm' switches control to the PCT or MCT model, for further
adjustments of the slopes.

The beginning time of the disturbance varies randomly each time a new
run occurs. By pressing the space bar, new runs can be done with the
same value of the slope of the reference signal's rise but a different
start of the disturbance. Thus you can see what happens when there
is or is not a disturbance occurring during the change in reference
signal.

MCT program by Hans Blom; PCT program and presentation by W. T. Powers
4 March 1997
}

uses
  dos, crt, graph, grutils;

var
  J, K, dt, r, x, u, v, maxu, xold, xpre, xsav: real;
  d, d1, d2, trued, t, pslope,mslope: real;
  gv, gx, rv, rx: real;
  xplot: integer;
  maxx, maxy,ycenter: integer;
  ch: char;
  numstr: string;
  fo: text;

function make_reference (t: real; var slope: real): real;
  {this function defines the setpoint at time t}
var ref: real;
begin
if t >= 3.0 then
begin
  ref := slope*(t - 3.0);
  if ref > 1.0 then ref := 1.0;
  make_reference := ref;
end
  else make_reference := 0.0;
end;

function true_disturb (t: real): real;
  {this function defines the true disturbance}
begin
  if (t < d1) or (t > d2) then
    true_disturb := 0.0
  else
    true_disturb := 50.0
end;

function do_observation: real;
{this function generates the x that the controller will observe}
begin
  do_observation := 2.0 * x - xold + u/K +
                     true_disturb(t)/K ;
end;

procedure plotit(baseline: integer);
begin
  xplot := round(50.0*t)+ 160;
  putpixel(xplot,baseline,white);
  putpixel(xplot,baseline - round(100.0*r),yellow);
  putpixel(xplot,baseline - round(100.0*x),white);
  putpixel(xplot,baseline - round(u),lightcyan);
  putpixel(xplot,baseline - round(trued),lightred);
end;

procedure legends;
begin
  clearviewport;
  setcolor(white);
  outtextxy(0,0,'Pointing angle');
  setcolor(yellow);
  outtextxy(0,15,'Ref level');
  setcolor(lightcyan);
  outtextxy(0,30,'Output torque');
  setcolor(lightred);
  outtextxy(0,45,'Disturbance');

end;

Procedure PCTmodel;
begin
setviewport(0,0,maxx,ycenter,ClipOn);
repeat {REPEAT WHOLE RUN}
  t := 0.0; {start at zero time}
  d := 0.0; {assume no disturbance initially}
  v := 0.0;
  x := 0.0;
  gv := 100.0;
  gx := 50.0;
  j := 1.0;

  d1 := 1.5 + 6.0*random;
  d2 := d1 + 3.0;
  maxu := 0.0;
  legends;
  str(pslope:5:3,numstr);
  setcolor(white);
  outtextxy(0,60,'Slope = '+numstr);
  outtextxy(150,100,'PCT MODEL');
repeat
{the control loop starts here}
  trued := true_disturb(t);
  r := make_reference (t+dt,pslope); {define reference}

{CONTROL SYSTEM EQUATIONS}
rv := gx* (r - x); {velocity ref level = output of position control}
u := gv*(rv - v); {output force = output of velocity control}

  if u < -100.0 then u := -100.0 else {limit output, if desired}
    if u > +100.0 then u := +100.0;
  x := x + v*dt + 0.5*(u+trued)*dt*dt/J;
  v := v + (u+trued)*dt/J;
  plotit(130);
  if u > maxu then maxu := u;
  t := t + dt;
until t >= 9.0; {at this point the loop ends}
ch := readkey;
if ch in ['=','+'] then pslope := pslope*1.5;
if ch in ['_','-'] then pslope := pslope/1.5;
until ch in ['q','Q','m','M'];
end;

Procedure MCTmodel;
begin
setviewport(0,ycenter+1,maxx,maxy - 20,ClipOn);
repeat {REPEAT WHOLE RUN}
  t := 0.0; {start at zero time}
  xold := 0.0; {start at zero position}
  x := xold; {and at zero velocity}
  d := 0.0; {assume no disturbance initially}
  d1 := 1.5 + 6.0*random;
  d2 := d1 + 3.0;
  maxu := 0.0;
  legends;
  str(mslope:5:3,numstr);
  setcolor(white);
  outtextxy(0,60,'Slope = '+numstr);
  outtextxy(150,100,'MCT MODEL');
repeat
{the control loop starts here}
  trued := true_disturb(t);
  r := make_reference (t+dt,mslope); {define reference}
  u := K * (r - 2.0 * x + xold) - d; {compute output}
  if u < -100.0 then u := -100.0 else {limit output, if desired}
    if u > +100.0 then u := +100.0;
  xpre := 2.0 * x - xold + u / K + d / K; {generate prediction}
  xsav := x; {save present x}
  x := do_observation; t := t + dt; {observe x}
  xold := xsav; {xold := previous x}
  d := d + K * (x - xpre); {estimate disturbance}
  plotit(130);
  if u > maxu then maxu := u;
until t >= 9.0; {at this point the loop ends}
ch := readkey;
if ch in ['=','+'] then mslope := mslope*1.5;
if ch in ['_','-'] then mslope := mslope/1.5;
until ch in ['q','Q','p','P'];
end;

{initialization}
begin
  clrscr; {clear screen}
  initgraphics;
  maxy := getmaxy;
  maxx := getmaxx;
  ycenter := (maxy+1) div 2;
  J := 10.0; {or whatever value...}
  dt := 0.01; {or whatever value...}
  K := (J / dt) / dt; {auxiliary constant}
  mslope := 0.2;
  pslope := 0.2;
  setcolor(white);
  outtextxy(0,maxy - 15,'q to quit, space to repeat, +/- to change slope');
  ch := 'm';
  repeat
  if ch in ['m','M'] then MCTmodel;
  if ch in ['p','P'] then PCTmodel;
  until ch in ['q','Q'];
  closegraph;
end.

[Hans Blom, 970305]

(Bill Powers (970304.0941 MST))

Physical systems can't change from one state to another instantly.

Physical systems _can_ change from one state to another within a
small time dt, if the state change is small enough. Whoever
introduced the "instantly" does not deserve a reward.

Bill, your comparison program looks great. I'm fully satisfied with
how you employed my code. I would, however, like to suggest some
small additions:

1. let both controllers run simultaneously on the same problem; that
allows instantaneous (there, I said it :wink: comparisons;

2. give a numerical value of the (integrated squared) error; the
graphical format doesn't show the (local and total) error clearly
enough;

3. do not only allow changes in slope, but also changes in J.

Otherwise you did a great job!

Greetings,

Hans

[From Bill Powers (970305.0955 MST)]

Hans Blom, 970305--

Physical systems can't change from one state to another instantly.

Physical systems _can_ change from one state to another within a
small time dt, if the state change is small enough. Whoever
introduced the "instantly" does not deserve a reward.

You're still arguing the same point that philosophers raised against
Liebnitz ("infinitesimals") and Newton ("fluxions"). The only way you can
get away from instantaneous transitions is to reduce dt all the way to the
limit of zero. (x(t + 0.5*dt) - x(t - 0.5*dt)]/dt becomes dx/dt only in the
limit as dt-->0. It's only in the limit, when dt = 0, that you make the
qualitative change to a continuous universe. And in that limit, you can't do
things like solving for x(t+dt) as you do. In the limit, x(t+dt) = x(t), and
the algebraic approach breaks down.

So as long as the steps in your discrete calculations of position occupy any
finite amount of time, the physical acceleration required to take each step
is infinite. The only reason it doesn't come out infinite in your mind is
that you divide the finite change in position by a finite length of time, as
if the velocity increased smoothly from v(t) to v(t+dt), DURING THE INVERVAL
DT. An underlying continuum is implied when you talk about changes during
the interval dt. In a discrete model, however, nothing can change "during
the interval." That happens only in your imagination, not in the mathematics
of discrete systems. This is why the maximum permissible slope of the
reference signal, in the MCT model, depends on the size of dt that you use.

If you reduce dt to 0.001 (from 0.01) in theo4mct, you will find that the
visible oscillations in your model begin at about 1/3 as much slope as
before. This is because the accelerations per step must be larger when you
reduce dt. If you calculate the peak output before the output limit is
applied, you find that for dt = 0.01, umax = 150, but for dt = 0.001, umax =
17,500 -- 100 times as great. Umax seems to go as the inverse square of dt,
reflecting the dt^2 in the denominator.

Bill, your comparison program looks great. I'm fully satisfied with
how you employed my code. I would, however, like to suggest some
small additions:

1. let both controllers run simultaneously on the same problem; that
allows instantaneous (there, I said it :wink: comparisons;

Thanks. I'll see if I can work that out, although you may find the method in
theo5mct satisfactory. In this version, posted this morning, you can go back
and forth between the models and adjust the slopes of the reference signals
independently, and compare the traces on the screen.

2. give a numerical value of the (integrated squared) error; the
graphical format doesn't show the (local and total) error clearly
enough;

At least until you persuade the MCT model to stop oscillating, or improve
the performance, there is no need. Also, such a comparison won't be
meaningful until both models are using the same (physically correct) model
of the theodolite -- I've already posted a note on this problem.

3. do not only allow changes in slope, but also changes in J.

That's on the agenda. When you change J, an adaptive model is required to
maintain peak performance (although the PCT model is relatively insensitive
to changes in J). I know how you will introduce adaptation, but I have to
work out a higher-level system that will sense something about the
performance of the control system and alter some system parameter to
maintain optimum performance. I've tested this by hand and it works quite
well, but I have to figure out what I was looking at in the graphical
display (to make the adjustment) that can be turned into a controlled
variable that could be sensed from inside the controller.

Another problem lurking in the future is how to handle a controller that
contains delays, when the physical system doesn't contain any delays. Right
now, both controllers contain a delay of 0.01 sec, the duration of one
iteration, which is set by the size of dt. The physical theodolite might
contain delays between application of force and commencement of
acceleration, but they will be, to put it mildly, a lot shorter than 0.01 sec.

Best,

Bill P.