Control systems and you
Somewhat out of my current character, I lead with a lyric from They Might Be Giants:
Turn it up, turn it down
Turn it up when the cold brings you down
When the heat bothers you turn it down
Turn it up, turn it down— They Might Be Giants, “Thermostat”
This is a song about a thermostat, a brilliant device contrived in 1883 to either turn off or turn on a heating/cooling system in order to favor a certain temperature. The traditional version of the thermostat is among the simplest examples of a negative-feedback control system, a very important class of device.
An “on-off” control system basically repeats the following ad infinitum. The following example is for a thermostat controlling a heater (with a generalized version in parentheses).
- Is the current temperature the same as the temperature we want? (Is the current state the same as—or similar enough to—the desired state?)
- If so, good—stop here and check again after a certain period of time or as soon as there is an indication that this may no longer be the case.
- If not, continue.
- Which direction, higher or lower, is the desired temperature relative to the current temperature? (How is the current state different than the state we want? Which direction should we be going?)
- If the right direction is higher, am I already heating? If lower, am I already not heating? (Am I already moving in the right direction?)
- If so, then we’re already doing what we need to be doing. (Our effort is already in the right direction.)
- If not, switch off (if on) or on (if off). (Switch our effort to the right direction.)
- Start over.
Note that the typical thermostat is an on-off control, meaning that there are exactly two modes to its operation—0% and 100%. In the middle of winter, when it’s 68°F in your house and you decide to crank it to 78°F, well, first of all, you must like it hot and enjoy high energy bills; 68’s always fine in my house. Anyway, you as a human know that you’ve turned up the set point by 10 degrees, which is a lot to do at once. What you may or may not have realized is that your furnace isn’t making any special effort to work faster than if you’d only turned it up 2 degrees. It’s just going to stay on as long as it takes to do its job and then kick off.
This is because an on-off system asks “if I’m too far in either direction, which direction?” but not “and by how much?” This is the domain of a linear control system.
One might liken a linear control system with a human being with his foot on the accelerator pedal of a car. (For the time being, we’ll ignore that the brake is also pretty handy for slowing down a car.) The new process is as follows:
- Is my current speed the speed I want? (Same as 1 above.)
- If so, good—stop here and check again after a certain period of time or as soon as there is an indication that this may no longer be the case.
- If not, continue.
- Which direction, faster or slower, is the desired speed relative to the current speed? (Same as 2 above.)
- If faster, push the pedal harder (if possible).
- If slower, ease off the pedal (if possible).
- In inexact terms (this is important), how different than the desired speed is the current speed? (What is the error, the magnitude of the necessary change?)
- If the desired speed is a little faster, push the pedal a little harder.
- If the desired speed is a lot faster, push the pedal a lot harder.
- If the desired speed is a little slower, ease off the pedal a little.
- If the desired speed is a lot slowed, ease off the pedal a lot.
- Start over.
What’s remarkable about a system like this is that it’s inexact by design. For example, if I’m driving 60mph and need to 70mph, I’m going to push the pedal harder. But how much harder? Can I state it with an exact measurement of radians per mile per hour? No. (It could possibly be done, but I hope nobody is that bored.) So I just push the pedal (control) and see what happens (feedback). If I end up too slow, I push harder. If I undershoot, I let up on the pedal. This trial-and-error is called oscillation and a system generally benefits from it being kept to a minimum.
The system seems to work in situations where
- the directions of feedback and control have a consistent relationship; e.g. pushing harder always means increase in speed and, conversely, an increase in speed requires pushing harder
- the magnitude of change at the control is at least somehow proportional to the magnitude of the resulting change in the feedback; e.g. pushing a little or a lot harder means going a little or a lot faster, respectively, with the ratio of change at the control to the change at the feedback being adjusted on the fly as necessary; if we push the pedal a little and the car bolts, we adjust our definitions so that pushing the pedal a little means a much smaller push than before
One application of this that I consider fun is a phase-locked loop (PLL), which is able to arbitrarily multiply a clock signal from e.g. a crystal. I’ve never messed with one directly, but the ones in some of the Microchip PIC devices are able to bump the 20MHz CPU clock to a whopping 96MHz, which is then divided (a much simpler operation) to 48MHz in order to implement the onboard USB peripheral.
If the driver analogy above made any sense, then PLLs are a piece of cake: For every 20 million pulses that are generated by the crystal, it has to generate 96 million pulses. Or, if you’re clever, for every 5 pulses from the crystal, generate 24—probably easier to count that way. It’s by no means trivial, but it’s straightforward.
Control: The PLL train is produced by a voltage-controlled oscillator (VCO), which is able to generate really, really fast pulse trains but must be tuned on the fly. (This can be replaced with some other form of controlled variable-frequency oscillator.) When it’s first kicked, it delivers a pulse train that is most likely not the right frequency.
Pre-processing: To correct it, the first thing we do is have available a frequency divider for each of the crystal (divide by 5) and the VCO output (divide by 24). A frequency divider is dead simple; for example, to divide a pulse train by 5, just do a transition on output for every 5 you count on input. Simple! Our goal is to make the pulse train of the crystal/5 match the VCO/24 as precisely as possible. When they match, the VCO output is exactly 24/5 of the crystal’s input. Then, we just pass the VCO output directly to wherever it’s needed.
Error: A phase detector sets about finding the difference between the VCO/24 and the crystal/5 trains, noting where the trains are not the same width as well as where they don’t line up even if they are the same frequency. A low-pass filter cleans up places where the difference is so slight that it should be ignored (i.e., where the differences are so insignificant that acknowledging them would hurt rather than help).
Feedback: The error value from the phase detector is fed back into the VCO.
And, as they say, viola…96MHz from 20MHz. Nifty, right?
If I get my way this weekend, I’ll have turned a PIC18F4550 into a bona fide peripheral. Just figured that a note or two about how this is possible might be in order…