Temperature control

[From Bill Powers (920616.1600) (The Control Systems Group)

Fang Zhong (Duke University 920616) --
Copy to CSGnet

Hello, Fang Zhong. You've been put in contact with a conference concerned
mainly with control theory as a tool for understanding behavior. As we use
pretty simple versions of control theory, maybe you've come to the right
place for a simple answer.

I have to make some guesses about the physical setup. I assume that your
heater is in contact with some thermal mass, perhaps water. So the mass
will heat up at a rate proportional to input power. There will also be a
thermal transport lag if the sensor is at all far from the heater. It's
mainly the transport lag that will cause the oscillations when you raise
the sensitivity. If you're using water, you can cut down on the transport
lag by madly stirring the water. But that's not your main problem.

Consider this line:

  vh2 = prev_vh * prev_vh + (2 * cur_r - target_r - prev_r) * dv_dr

If you want to control temperature, you have to compare sensed temperature
with reference or target temperature. So the error signal would just be
(target_r - cur_r).

As you are using 2 * cur_r and subtracing prev_r, I assume you're adding
some first derivative of the error signal: that is,

  total error = target - cur_r - (cur_r - prev_r)
                 <--error --> <-- deriv of error -->

This is my standard way of writing the error signal -- the sensor signal is
always subtracted from the reference signal. No particular reason, that's
just my convention. It keeps the feedback negative with all other constants
in the loop positive.

Now you want the heater voltage vh to be the integral of the error signal.
If you add the error signal to the SQUARE of the heater voltage (vh2),
you'll get a hybrid between the square of the integral and the integral of
the square. I don't think you want either one. It would be best to compute
first just the integral of the error:

   vh2 = vh2 + (target_r - cur_r) - (cur_r - prev_r)

Now vh2 doesn't mean the square, it's just used as a dummy variable
(initialized to zero).

If you want heating rate to be linear with error, and I think this is best,
you should output a heater voltage proportional to the square root of vh2,
because power output goes as vh*vh. So your step

        vh = sqrt(vh2)

is OK. It would be best to precede this step by

if(vh2 < 0) vh2 = 0

to avoid accidentally taking the square root of a negative number.

This will result in a linear heating system with integral error control,
some first-derivative phase advance, and another integration in the
environmental part of the loop that converts power output to rate of change
of temperature (temperature is roughly the integral of power output). If
the derivative contribution is large enough, you will get a system that
looks like a single integrator, and it will be stable save for the effects
of transport lag.

You need to be able to vary the amount of first derivative in relation to
the error signal, changing the first program line above to:

   vh2 = vh2 + k1*(target_r - cur_r) - k2*(cur_r - prev_r).

By setting k1 VERY small and k2 zero, you can get a system that approaches
the reference temperature and stays there. It will act very slowly. Then
you can start increasing k1 to create oscillatory control, then k2 to
eliminate the oscillations. Eventually you will arrive at values of k1 and
k2 that give you the fastest possible control without oscillation. You
won't be able to go any faster than that because of transport lags.

Let us know how it works!


Bill Powers