{"version":1,"lectureId":"01M14TYE5YQN06G7H8ST7F6QPD","attempt":0,"publication":{"slug":"pid-control-one-term-at-a-time","title":"PID Control, One Term at a Time","subject":"engineering","summary":"A cruise control has to hold a hundred kilometres an hour while the road tilts under it. This lecture builds the controller that does it, one term at a time, on a single response curve you watch the whole way through: proportional action, which reacts to the error now and always leaves a steady gap; integral action, which accumulates the error's history and finally erases that gap, at the cost of overshoot and windup; and derivative action, which reads the slope of the error and leans against the approach. The three are then assembled into the standard PID law and tuned, with each gain pushed too far in turn, so the trade between rise time, overshoot and noise is something you see rather than something you are told.","metaDescription":"Build a PID controller one term at a time on a cruise control: proportional offset, integral windup, derivative damping, and tuning.","transcript":"Every machine that has to hold something steady is solving the same problem. A cruise control holding a speed. A thermostat holding a room temperature. The world knocks it off target, and it has to push back, by exactly the right amount and no more. So here is the question this whole lecture answers. How does a machine hold a setpoint that the world keeps knocking it off? PID answers with three corrections: the present error, its accumulated past, and its direction of travel. Let's make it concrete. A car on a road, and a driver who sets the cruise control to one hundred kilometres an hour. Left alone with no extra throttle, this car rolls along at sixty. And it does not respond instantly. Ask for more throttle, and the engine takes about a second to deliver the extra pull, and the car takes a few seconds more to work that pull into speed. Every real plant has that lag, and it is the reason control is hard at all. That target has a name. It's the setpoint, r. What the car is actually doing at each instant we'll call v of t. And the whole job of a controller is to make v equal r, and then keep it there. Now, the naive fix. Guess the throttle. Find the setting that holds a hundred on flat road, push the pedal to exactly there, and leave it. And on flat road, it works. And then, fifteen seconds in, the road tilts up. The grade swallows part of the engine's pull, and the speed sags. The throttle does not move, because nothing in this machine is looking at the speed. It settles twenty kilometres an hour below target, and it stays there for good. And notice where the fault is. The machine is not wrong about the throttle. It is wrong because it has no idea what the speed is doing. Nothing measures the output, so nothing can react to it. That is the whole disease of an open loop. It guesses, and it never checks. So let's close the loop. Measure the speed, subtract it from the setpoint, and call that difference the error. The error is the only thing our controller gets to look at. So everything from here is one question. Given the error, what throttle should I command? That is u equals some function of e, and the rest of this lecture is filling that function in. There are three classic answers, and they stack. Proportional, which reacts to the error right now. Integral, which remembers the whole history of the error. And derivative, which watches where the error is heading. So, the first answer, and it is the one everybody invents for themselves. Look at the error right now, and push back in proportion to it. Big error, big correction. Small error, small correction. Nothing else. In symbols, that is u equals K p times e. One number to pick, the proportional gain, and that is the entire controller. So let's watch it drive. Same car, same hill at fifteen seconds. We start with the gain set to one: the moment we switch on, the error is forty, so the controller asks for forty units of throttle, and the car pulls away. Notice the shape it makes. It starts flat, because the engine has not delivered anything yet. Then it swings up hard while the error is big. And it flattens out as the error shrinks, because the correction shrinks with it. And then it stops. Eighty kilometres an hour. Twenty short of the setpoint, and it will sit there all day. The controller is running, the loop is closed, and the car is still twenty short. And this is not a bug you can tune away. It is arithmetic. This controller commands a throttle proportional to the error, so if the error ever reached zero, the command would be zero as well, and with no extra throttle the car falls straight back to sixty. Say that again, because it is the crux. The only way this controller can command throttle is to be wrong. Ask it to hold a hundred and it must run below a hundred, permanently, to have any error left to work with. So the error cannot reach zero. It stops where the throttle it produces is exactly the throttle the car needs. Solve for that point and you get this. The error left over is the whole forty kilometre gap, divided by one plus the gain. Which tells you exactly what raising the gain buys. Turn it up to three, and the leftover error is ten. The car holds ninety, and it gets there quicker. Turn it up to nine and the error is down to four. But look what has happened to the shape. It arrives fast, sails past the setpoint, and takes a couple of swings to settle. And notice why that overshoot appeared at all. The engine's pull lags behind the command. By the time the car is on target there is still a large pull in the pipeline, and that surplus carries it straight past the line. Push on to fifteen and the ringing is worse again, while the offset has only crept from four down to two and a half. You can chase that gap as far as your patience for overshoot allows. You never reach zero. And now the hill, which is the same story told louder. Every one of these curves drops when the grade hits, and every one settles at a new, lower speed. With the gain at three the car held ninety on the flat. On the hill it holds eighty five. Same controller, same gain, twice the error. A bigger load needs a bigger throttle, and the only way this controller can command a bigger throttle is to be further from the setpoint. It is paid in error. So proportional control is fast, it is simple, and it is structurally incapable of finishing the job. To kill that last gap, the controller needs something proportional can never have. It needs a memory. Proportional control reacts to the error right now, and right now is exactly what strands it. It has no way of knowing that this same small error has been sitting there, unfixed, for the last ten seconds. What it needs is a record. So here is the error from that last run, plotted on its own. It starts at forty, falls fast while the correction is big, flattens out at ten, and sits there until fifteen seconds. Then the hill makes the error jump and settle higher. One thing to keep straight: this is the error, not the speed. Zero on this axis means the car is exactly on target, and every kilometre of gap up here is a kilometre the controller has failed to close. Now, instead of reading the height of this curve, add it up. Every second that goes by with an error of ten piles ten more onto the total. That accumulation is the area underneath the curve, from the moment we switched on up to now. And watch what that pile does while the error is stuck. It grows, and it keeps growing, and nothing ever takes anything off it. A leftover error that proportional control is perfectly happy with turns into an accumulation that gets bigger without limit. So that is our second term. Add to the throttle a piece proportional to the accumulated error, the integral of e, with a gain of its own, K i. And now ask where this controller can possibly come to rest. Suppose it settles with any error at all left over, even half a kilometre an hour. Then the integral keeps climbing, so the throttle keeps climbing, so the speed keeps climbing. It cannot be at rest. The only value of the error it can hold still at is exactly zero. That is a strong claim, so let me put it plainly. A controller with an integral term, on a plant like this one, drives the steady error to zero. Not small. Not nearly. Zero. So let's drive it. Grey is proportional alone, stuck at ninety. Green is the same proportional gain with the integral added, K i equal to one. It takes its time, because it has to build the pile up before the extra throttle amounts to anything. But it arrives. And it arrives exactly on the line, with no offset at all, which proportional control could not do at any gain. Then the hill hits. The speed sags, so the error comes back, so the pile starts growing again, and the controller walks the car back up to a hundred and holds it there. That is the integral's whole job. It refuses to accept a leftover error, because a leftover error is a pile that never stops growing. But that memory costs you. Turn K i up to two and a half, and by the time the speed reaches the setpoint the accumulator has already commanded a large throttle. Being on target does not empty the pile. It only stops adding to it. So the car sails past, and the error has to go negative, the car has to spend time above the setpoint, before that accumulation comes back down. That is the overshoot and the ringing you are looking at. Taken to the extreme it has a name: integrator windup. If the throttle saturates, or the car is held back for a while, the accumulator keeps piling up error it cannot act on, and the plant spends the next several seconds paying it back. So proportional gets us moving, integral finishes the job, and between them they have bought us an oscillation. The third term is the cure for that. The trouble with that last run is that the controller only discovered it was going too fast after it had already gone too fast. Everything it knows is about the present and about the past. Nobody in there is looking ahead. But there is a look ahead sitting right in the data. Here is the error again, this time from an aggressive proportional plus integral tuning, the kind that rings. And at any instant we can ask a different question about it. Not how big is the error, but how fast is it changing. That is the slope of this curve, and here it is at two seconds in. The error is still about twelve kilometres an hour, and it is falling at roughly twelve kilometres an hour each second. At that rate the car reaches the target in about one second. And that number is a prediction. It is the controller's only honest statement about the future, and it costs nothing to compute, because it is right there in the measurement it already has. It is also the warning that proportional and integral cannot hear. Proportional sees a large error and pushes. The integral sees a large pile and pushes. Neither one knows that the correction already in the pipeline is more than enough. So give the controller a third term. A piece proportional to the rate of change of the error, with a gain of its own, K d. And read the sign carefully, because the sign is the whole idea. When the error is falling, d e by d t is negative, so this term subtracts throttle. The faster you are closing in, the harder it eases off. It is a brake that comes on only when you are approaching quickly. Now watch it along the whole run. Every time the car swings toward the line, the slope is steep and the term leans against the motion. Every time it swings away, the sign flips and the term leans the other way. And once the swinging stops, the curve goes flat and the slope is zero. That last part matters. At steady state, derivative action is silent. It cannot fix an offset and it cannot cause one. It only ever speaks while things are changing. So here is that same aggressive tuning, with it and without it. Red is proportional plus integral, the run we just took apart. Green is the same two gains with derivative added, K d equal to three. The two leave the line at the same speed, because early on the error is huge and the proportional term dominates both of them. But the peak overshoot falls from about seventeen kilometres an hour to about ten, the ringing shrinks, and the green curve is within one kilometre an hour of the setpoint by about six seconds. Same car, same integral, one extra term. And the hill gets the same treatment, a shallow dip instead of a plunge, because the moment the speed starts to fall the derivative term sees the slope and pushes back, before the error has had time to grow. So there is the whole controller. Three terms, one error signal. The present, the past, and the projected future, added up into a single number and sent to the throttle. One caution before we tune it. That derivative is the slope of a measured signal, and real measurements are noisy. Differentiate noise and you amplify it, which is why practical controllers filter the derivative, or take it from the measurement rather than from the error. So. Three gains, and one system that has to rise quickly, settle cleanly, and hold. Tuning is nothing more than deciding how much of each of the three answers you want. Proportional is the present. It reacts to the error you have right now, it is your main lever on how quickly you respond, and on its own it always leaves a gap. Integral is the past. It accumulates what proportional keeps leaving behind, and it is the only one of the three that can drive the steady error to zero. It buys you accuracy, and it costs you overshoot. Derivative is the future. It reads the slope and leans against fast change. It buys you damping, and it costs you sensitivity to noise. Here is the tuning we ended on. K p six, K i three, K d three. Quick off the line, one small overshoot, settled inside about six seconds, and it takes the hill in its stride. And watch which term is doing the work along that curve. In the first second it is nearly all proportional. Through the middle of the rise, derivative is holding it back. And after the hill, the last few kilometres an hour are closed by the integral, slowly, with the other two almost silent. Now let's break it, one gain at a time, and watch the same curve move. Triple the proportional gain and the response gets snappy and impatient. It hits harder, it swings wider, and it argues with itself for a good deal longer before it settles. Put that back, and turn the integral up instead. The accumulator gets ahead of the plant, so the overshoot grows, and there is a long slow ring while the pile is paid back down. And too much derivative goes the other way. It is so eager to lean against any change at all that it drags its feet, and the rise slows right down. In a real plant it would also be turning every twitch of sensor noise into a twitch of the throttle. The three broken tunings make the trade explicit. Too much proportional gain buys speed with overshoot and fast ringing. Too much integral gain buys persistence with overshoot and slow ringing. Too much derivative gain buys resistance to change with a slower rise and greater noise sensitivity. Which is also why tuning rules exist. Ziegler and Nichols, relay tuning, and the rest of them are recipes for finding a decent corner of that trade without walking the whole space by hand. So that is P I D. One error signal, read three ways. What it is, what it has been, and where it is going. Multiply each reading by a gain, add them up, and send the sum to the actuator. It is a strikingly small idea, and it runs a startling fraction of the machines around you. The ovens, the drones, the disk drives, the cruise control in the car you came here in. Three terms. One error.","watch":{"version":1,"scenes":[{"title":"Holding a Setpoint","start":0,"end":163.50145833333332,"objects":{"axes":"an Axes (x_range=(0.0, 30.0), y_range=(50.0, 120.0), x_ticks_every=5.0)","card":"a Title that says \"Feedback Control — PID Control, One Term at a Time\"","engine_lag":"a Vector [red] labelled \"upright(\"engine\")\" drawn in axes (start=(0.0, 55.0), end=(1.0, 55.0))","eq_error":"a Math [text] that says \"$e(t) = r - v(t)$\"","eq_law":"a Math [text] that says \"$u(t) = C(e(t))$\"","eq_set":"a Math [text] that says \"$r = 100 thin upright(\"km/h\")$\"","full_law":"a Math [text] that says \"$u(t) = K_p e(t) + K_i integral_0^t e(s) dif s + K_d dot(e)(t)$\"","gap_dot":"a PlotPoint [red] drawn in axes (target='open_curve', x=27.0)","gap_line":"a Line [red] labelled \"e\" drawn in axes (start=(27.0, 80.35775546255915), end=(27.0, 100.0))","hill_line":"a Line [gray] drawn in axes (start=(15.0, 52.0), end=(15.0, 116.0), dashed=True)","open_curve":"a FunctionPlot [blue] labelled \"v(t)\" drawn in axes (function=<function>)","point":"a Point [yellow] drawn in axes (location=(15.0, 99.59808288114526))","point_2":"a Point [yellow] drawn in axes (location=(27.0, 80.35775546255915))","question":"a Panel that says \"How does a machine hold a setpoint that the world keeps knocking it off?\"","setpoint_line":"a Line [yellow] drawn in axes (start=(0.0, 100.0), end=(30.0, 100.0), dashed=True)","speed_lag":"a Vector [green] labelled \"upright(\"car\")\" drawn in axes (start=(1.0, 55.0), end=(4.0, 55.0))"},"beats":[{"start":0,"say":"Every machine that has to hold something steady is solving the same problem. A cruise control holding a speed. A thermostat holding a room temperature. The world knocks it off target, and it has to push back, by exactly the right amount and no more.","live":[],"does":[[0,"card is shown on the screen, written out."],[1.5,"card: enter:write-left-to-right."],[14.5125,"card is hidden from the screen — left the board."]]},{"start":15.712499999999999,"say":"So here is the question this whole lecture answers. How does a machine hold a setpoint that the world keeps knocking it off? PID answers with three corrections: the present error, its accumulated past, and its direction of travel.","live":null,"does":[[16.723,"question is shown on the screen, written out."],[23.712,"full_law is shown on the screen, written out."],[31.560499999999998,"full_law moves to a new place on the board."]]},{"start":32.7605,"say":"Let's make it concrete. A car on a road, and a driver who sets the cruise control to one hundred kilometres an hour. Left alone with no extra throttle, this car rolls along at sixty.","live":["full_law","question"],"does":[[35.21000000000001,"axes is shown on the screen, written out."],[37.962,"setpoint_line is shown on the screen, written out."]]},{"start":44.4365,"say":"And it does not respond instantly. Ask for more throttle, and the engine takes about a second to deliver the extra pull, and the car takes a few seconds more to work that pull into speed. Every real plant has that lag, and it is the reason control is hard at all.","live":["full_law","question","axes","setpoint_line"],"does":[[49.754,"engine_lag is shown on the screen, drawn."],[52.749,"speed_lag is shown on the screen, drawn."]]},{"start":61.012,"say":"That target has a name. It's the setpoint, r. What the car is actually doing at each instant we'll call v of t. And the whole job of a controller is to make v equal r, and then keep it there.","live":["full_law","question","axes","setpoint_line","engine_lag","speed_lag"],"does":[[61.012,"engine_lag is hidden from the screen."],[61.012,"speed_lag is hidden from the screen."],[63.288,"eq_set is shown on the screen, written out."]]},{"start":74.6965,"say":"Now, the naive fix. Guess the throttle. Find the setting that holds a hundred on flat road, push the pedal to exactly there, and leave it. And on flat road, it works.","live":["full_law","question","eq_set","axes","setpoint_line"],"does":[[76.54299999999999,"open_curve is shown on the screen, drawn."]]},{"start":86.385,"say":"And then, fifteen seconds in, the road tilts up.","live":["full_law","question","eq_set","axes","setpoint_line","open_curve"],"does":[[87.685,"point is shown on the screen, grown."],[89.485,"hill_line is shown on the screen, written out."],[89.685,"point is hidden from the screen."]]},{"start":91.0715,"say":"The grade swallows part of the engine's pull, and the speed sags. The throttle does not move, because nothing in this machine is looking at the speed. It settles twenty kilometres an hour below target, and it stays there for good.","live":["full_law","question","eq_set","axes","setpoint_line","open_curve","hill_line"],"does":[[100.22,"gap_dot is shown on the screen, written out."],[100.22,"gap_line is shown on the screen, written out."],[100.569,"point_2 is shown on the screen, grown."],[102.569,"point_2 is hidden from the screen."]]},{"start":105.2555,"say":"And notice where the fault is. The machine is not wrong about the throttle. It is wrong because it has no idea what the speed is doing. Nothing measures the output, so nothing can react to it.","live":["full_law","question","eq_set","axes","setpoint_line","open_curve","hill_line","gap_dot","gap_line"],"does":[[105.77799999999999,"gap_line is indicated — a transient flash."],[112.78999999999999,"open_curve is indicated — a transient flash."]]},{"start":117.9525,"say":"That is the whole disease of an open loop. It guesses, and it never checks. So let's close the loop. Measure the speed, subtract it from the setpoint, and call that difference the error.","live":null,"does":[[122.886,"open_curve is indicated — a transient flash."],[129.562,"eq_error is shown on the screen, written out."],[130.08499999999998,"eq_error (the \"r - v(t)\" part) is emphasized."]]},{"start":131.416,"say":"The error is the only thing our controller gets to look at. So everything from here is one question. Given the error, what throttle should I command? That is u equals some function of e, and the rest of this lecture is filling that function in.","live":["full_law","question","eq_set","eq_error","axes","setpoint_line","open_curve","hill_line","gap_dot","gap_line"],"does":[[131.416,"eq_error (the \"r - v(t)\" part) is no longer emphasized."],[142.20099999999996,"eq_law is shown on the screen, written out."]]},{"start":147.852,"say":"There are three classic answers, and they stack. Proportional, which reacts to the error right now. Integral, which remembers the whole history of the error. And derivative, which watches where the error is heading.","live":["full_law","question","eq_set","eq_error","eq_law","axes","setpoint_line","open_curve","hill_line","gap_dot","gap_line"],"does":[[151.997,"full_law (the \"K_p e(t)\" part) is emphasized."],[155.63,"full_law (the \"K_i integral_0^t e(s) dif s\" part) is emphasized."],[155.63,"full_law (the \"K_p e(t)\" part) is no longer emphasized."],[159.55499999999998,"full_law (the \"K_d dot(e)(t)\" part) is emphasized."],[159.55499999999998,"full_law (the \"K_i integral_0^t e(s) dif s\" part) is no longer emphasized."],[162.20979166666666,"full_law (the \"K_d dot(e)(t)\" part) is no longer emphasized."],[162.45979166666666,"axes is hidden from the screen — left the board."],[162.45979166666666,"setpoint_line is hidden from the screen — axes left the board."],[162.45979166666666,"open_curve is hidden from the screen — axes left the board."],[162.45979166666666,"hill_line is hidden from the screen — axes left the board."],[162.45979166666666,"gap_dot is hidden from the screen — axes left the board."],[162.45979166666666,"gap_line is hidden from the screen — axes left the board."],[162.45979166666666,"eq_error is hidden from the screen — left the board."],[162.45979166666666,"eq_law is hidden from the screen — left the board."],[162.45979166666666,"eq_set is hidden from the screen — left the board."],[162.45979166666666,"full_law is hidden from the screen — left the board."],[162.45979166666666,"question is hidden from the screen — left the board."]]}]},{"title":"Proportional Action","start":163.50145833333332,"end":371.3833333333333,"objects":{"axes":"an Axes (x_range=(0.0, 30.0), y_range=(50.0, 120.0), x_ticks_every=5.0)","claim":"a Math [text] that says \"$e = 0 quad => quad u = 0$\"","concept":"a Panel that says \"Command a correction proportional to the error. Big error, big push; small error, small push. The constant $K_p$ is the proportional gain.\"","curve_fifteen":"a FunctionPlot [red] labelled \"K_p = 15\" drawn in axes (function=<function>)","curve_nine":"a FunctionPlot [magenta] labelled \"K_p = 9\" drawn in axes (function=<function>)","curve_one":"a FunctionPlot [blue] labelled \"K_p = 1\" drawn in axes (function=<function>)","curve_three":"a FunctionPlot [green] labelled \"K_p = 3\" drawn in axes (function=<function>)","gap_line":"a Line [red] labelled \"e_infinity\" drawn in axes (start=(12.0, <VariableNumber settled = 97.5>), end=(12.0, 100.0))","heading":"a Heading that says \"Proportional: React to the Error Now\"","heading_two":"a Heading that says \"Why the Offset Has to Be There\"","hill_line":"a Line [gray] drawn in axes (start=(15.0, 52.0), end=(15.0, 116.0), dashed=True)","law":"a Math [text] that says \"$u = K_p e$\"","point":"a Point [yellow] drawn in axes (location=(0.5, 61.34853565529148))","point_2":"a Point [yellow] drawn in axes (location=(2.5, 73.64920058908646))","point_3":"a Point [yellow] drawn in axes (location=(10.0, 80.0353124059384))","point_4":"a Point [yellow] drawn in axes (location=(12.0, 90.00333009852743))","point_5":"a Point [yellow] drawn in axes (location=(12.0, 95.99549961921497))","point_6":"a Point [yellow] drawn in axes (location=(12.0, 97.49480466706471))","point_7":"a Point [yellow] drawn in axes (location=(12.0, 90.00333009852743))","point_8":"a Point [yellow] drawn in axes (location=(27.0, 85.00164088992261))","result":"a Math [text] that says \"$e_infinity = frac(40, 1 + K_p) eq.not 0$\"","setpoint_line":"a Line [yellow] drawn in axes (start=(0.0, 100.0), end=(30.0, 100.0), dashed=True)","settled":"a VariableNumber (initial_value=80.0)","work":"a Derivation [text] that says \"$e_infinity &= r - v_infinity \\ &= frac(r - v_0, 1 + K_p) \\ &= frac(40, 1 + K_p) thin upright(\"km/h\")$\""},"beats":[{"start":163.50145833333332,"say":"So, the first answer, and it is the one everybody invents for themselves. Look at the error right now, and push back in proportion to it. Big error, big correction. Small error, small correction. Nothing else.","live":[],"does":[[163.50145833333332,"heading is shown on the screen, written out."],[171.15245833333333,"concept is shown on the screen, written out."]]},{"start":179.91445833333333,"say":"In symbols, that is u equals K p times e. One number to pick, the proportional gain, and that is the entire controller.","live":["concept","heading"],"does":[[180.66845833333332,"law is shown on the screen, written out."]]},{"start":189.75595833333333,"say":"So let's watch it drive. Same car, same hill at fifteen seconds. We start with the gain set to one: the moment we switch on, the error is forty, so the controller asks for forty units of throttle, and the car pulls away.","live":["concept","law","heading"],"does":[[190.4984583333333,"axes is shown on the screen, written out."],[190.4984583333333,"setpoint_line is shown on the screen, written out."],[190.4984583333333,"hill_line is shown on the screen, written out."],[196.74545833333332,"curve_one is shown on the screen, drawn."]]},{"start":205.01945833333332,"say":"Notice the shape it makes. It starts flat, because the engine has not delivered anything yet. Then it swings up hard while the error is big. And it flattens out as the error shrinks, because the correction shrinks with it.","live":["concept","law","axes","heading","setpoint_line","hill_line","curve_one"],"does":[[207.41145833333331,"point is shown on the screen, grown."],[209.41145833333331,"point is hidden from the screen."],[211.79945833333332,"point_2 is shown on the screen, grown."],[213.79945833333332,"point_2 is hidden from the screen."],[215.00345833333333,"point_3 is shown on the screen, grown."],[217.00345833333333,"point_3 is hidden from the screen."]]},{"start":219.67895833333333,"say":"And then it stops. Eighty kilometres an hour. Twenty short of the setpoint, and it will sit there all day. The controller is running, the loop is closed, and the car is still twenty short.","live":null,"does":[[221.89645833333333,"gap_line is shown on the screen, written out."]]},{"start":233.78995833333332,"say":"And this is not a bug you can tune away. It is arithmetic. This controller commands a throttle proportional to the error, so if the error ever reached zero, the command would be zero as well, and with no extra throttle the car falls straight back to sixty.","live":["concept","law","axes","heading","setpoint_line","hill_line","curve_one","gap_line"],"does":[[236.77345833333334,"concept is hidden from the screen — left the board."],[236.77345833333334,"heading is hidden from the screen — left the board."],[236.77345833333334,"law is hidden from the screen — left the board."],[236.77345833333334,"heading_two is shown on the screen, written out."],[236.77345833333334,"claim is shown on the screen, written out."],[242.1954583333333,"claim (the \"e = 0\" part) is emphasized."],[244.0874583333333,"claim (the \"e = 0\" part) is no longer emphasized."],[244.0874583333333,"claim (the \"u = 0\" part) is emphasized."]]},{"start":250.16795833333333,"say":"Say that again, because it is the crux. The only way this controller can command throttle is to be wrong. Ask it to hold a hundred and it must run below a hundred, permanently, to have any error left to work with.","live":["axes","setpoint_line","hill_line","curve_one","gap_line","claim","heading_two"],"does":[[250.16795833333333,"claim (the \"u = 0\" part) is no longer emphasized."],[258.64345833333334,"work is shown on the screen, written out."],[258.64345833333334,"work (the \"r\" part) is emphasized."],[260.01345833333335,"work (the \"r\" part) is no longer emphasized."],[260.01345833333335,"work (the \"v_infinity\" part) is emphasized."],[264.08845833333334,"work (the \"v_infinity\" part) is no longer emphasized."]]},{"start":264.6884583333333,"say":"So the error cannot reach zero. It stops where the throttle it produces is exactly the throttle the car needs. Solve for that point and you get this. The error left over is the whole forty kilometre gap, divided by one plus the gain.","live":null,"does":[[271.5964583333333,"work is shown on the screen, written out."],[277.31945833333333,"work is shown on the screen, written out."],[277.9234583333333,"work (the \"1 + K_p\" part) is emphasized."],[279.2819583333333,"work (the \"1 + K_p\" part) is no longer emphasized."]]},{"start":279.88195833333333,"say":"Which tells you exactly what raising the gain buys. Turn it up to three, and the leftover error is ten. The car holds ninety, and it gets there quicker.","live":null,"does":[[279.88195833333333,"curve_one is hidden from the screen."],[284.3054583333333,"curve_three is shown on the screen, drawn."],[288.1714583333333,"gap_line is redrawn as the numbers it depends on change."],[288.1714583333333,"point_4 is shown on the screen, grown."],[288.1714583333333,"settled ticks to 90.0."],[289.6114583333333,"curve_three is indicated — a transient flash."],[290.1714583333333,"point_4 is hidden from the screen."]]},{"start":290.9884583333333,"say":"Turn it up to nine and the error is down to four. But look what has happened to the shape. It arrives fast, sails past the setpoint, and takes a couple of swings to settle.","live":["axes","setpoint_line","hill_line","gap_line","claim","heading_two","curve_three"],"does":[[290.9884583333333,"curve_three is hidden from the screen."],[291.94045833333337,"curve_nine is shown on the screen, drawn."],[293.40345833333333,"gap_line is redrawn as the numbers it depends on change."],[293.40345833333333,"point_5 is shown on the screen, grown."],[293.40345833333333,"settled ticks to 96.0."],[295.40345833333333,"point_5 is hidden from the screen."]]},{"start":302.1419583333333,"say":"And notice why that overshoot appeared at all. The engine's pull lags behind the command. By the time the car is on target there is still a large pull in the pipeline, and that surplus carries it straight past the line.","live":["axes","setpoint_line","hill_line","gap_line","claim","heading_two","curve_nine"],"does":[]},{"start":315.23445833333335,"say":"Push on to fifteen and the ringing is worse again, while the offset has only crept from four down to two and a half. You can chase that gap as far as your patience for overshoot allows. You never reach zero.","live":null,"does":[[315.23445833333335,"curve_nine is hidden from the screen."],[316.2214583333334,"curve_fifteen is shown on the screen, drawn."],[317.2664583333334,"curve_fifteen is indicated — a transient flash."],[320.84245833333335,"gap_line is redrawn as the numbers it depends on change."],[320.84245833333335,"point_6 is shown on the screen, grown."],[320.84245833333335,"settled ticks to 97.5."],[322.84245833333335,"point_6 is hidden from the screen."],[325.81145833333335,"result is shown on the screen, written out."],[325.81145833333335,"result (the \"eq.not 0\" part) is emphasized."],[327.3439583333333,"result (the \"eq.not 0\" part) is no longer emphasized."]]},{"start":327.9439583333333,"say":"And now the hill, which is the same story told louder. Every one of these curves drops when the grade hits, and every one settles at a new, lower speed.","live":["axes","setpoint_line","hill_line","gap_line","claim","result","heading_two","curve_fifteen"],"does":[[327.9439583333333,"curve_fifteen is hidden from the screen."],[327.9439583333333,"gap_line is hidden from the screen."],[330.1844583333333,"curve_three is shown on the screen, written out."],[334.2134583333333,"hill_line is indicated — a transient flash."]]},{"start":338.3779583333333,"say":"With the gain at three the car held ninety on the flat. On the hill it holds eighty five. Same controller, same gain, twice the error. A bigger load needs a bigger throttle, and the only way this controller can command a bigger throttle is to be further from the setpoint. It is paid in error.","live":["axes","setpoint_line","hill_line","claim","result","heading_two","curve_three"],"does":[[339.09745833333335,"curve_three is indicated — a transient flash."],[340.47945833333335,"point_7 is shown on the screen, grown."],[342.47945833333335,"point_7 is hidden from the screen."],[343.59045833333334,"point_8 is shown on the screen, grown."],[345.59045833333334,"point_8 is hidden from the screen."]]},{"start":357.6229583333333,"say":"So proportional control is fast, it is simple, and it is structurally incapable of finishing the job. To kill that last gap, the controller needs something proportional can never have. It needs a memory.","live":null,"does":[[370.34166666666664,"axes is hidden from the screen — left the board."],[370.34166666666664,"setpoint_line is hidden from the screen — axes left the board."],[370.34166666666664,"hill_line is hidden from the screen — axes left the board."],[370.34166666666664,"curve_three is hidden from the screen — axes left the board."],[370.34166666666664,"claim is hidden from the screen — left the board."],[370.34166666666664,"heading_two is hidden from the screen — left the board."],[370.34166666666664,"result is hidden from the screen — left the board."],[370.34166666666664,"work is hidden from the screen — left the board."]]}]},{"title":"Integral Action","start":371.3833333333333,"end":599.4309166666667,"objects":{"concept":"a Panel that says \"Add a correction proportional to the accumulated error, so a small error that refuses to go away eventually commands a large push. The constant $K_i$ is the integral gain.\"","curve_p":"a FunctionPlot [gray] labelled \"K_i = 0\" drawn in response_axes (function=<function>)","curve_pi":"a FunctionPlot [green] labelled \"K_i = 1\" drawn in response_axes (function=<function>)","curve_pi_hot":"a FunctionPlot [red] labelled \"K_i = 2.5\" drawn in response_axes (function=<function>)","elapsed":"a VariableNumber","error_axes":"an Axes (x_range=(0.0, 30.0), y_range=(-5.0, 45.0), x_ticks_every=5.0)","error_curve":"a FunctionPlot [red] labelled \"e(t)\" drawn in error_axes (function=<function>)","error_hill_line":"a Line [gray] drawn in error_axes (start=(15.0, -3.0), end=(15.0, 42.0), dashed=True)","heading":"a Heading that says \"Integral: Remember the Error\"","heading_two":"a Heading that says \"What the Memory Buys, and What It Costs\"","hill_line":"a Line [gray] drawn in response_axes (start=(15.0, 52.0), end=(15.0, 116.0), dashed=True)","law":"a Math [text] that says \"$u = K_p e$\"","pile":"an AreaUnder [blue] drawn in error_axes (x_range=(0.0, <VariableNumber elapsed = 30.0>), opacity=0.35, target='error_curve')","point":"a Point [yellow] drawn in error_axes (location=(15.0, 10.000904500763426))","point_2":"a Point [yellow] drawn in error_axes (location=(12.0, 9.996669901472572))","point_3":"a Point [yellow] drawn in response_axes (location=(12.0, 90.00333009852743))","point_4":"a Point [yellow] drawn in response_axes (location=(12.0, 100.0997004952489))","point_5":"a Point [yellow] drawn in response_axes (location=(16.0, 95.09080651531968))","point_6":"a Point [yellow] drawn in response_axes (location=(27.0, 99.9004908514925))","point_7":"a Point [yellow] drawn in response_axes (location=(4.0, 115.76131755621778))","point_8":"a Point [yellow] drawn in response_axes (location=(4.0, 115.76131755621778))","point_9":"a Point [yellow] drawn in response_axes (location=(6.0, 92.32492436659642))","response_axes":"an Axes (x_range=(0.0, 30.0), y_range=(50.0, 120.0), x_ticks_every=5.0)","setpoint_line":"a Line [yellow] drawn in response_axes (start=(0.0, 100.0), end=(30.0, 100.0), dashed=True)","windup":"a Panel that says \"Integrator windup: while the actuator is saturated the pile keeps growing on error the controller cannot act on, and the plant pays it back afterwards.\"","zero_line":"a Line [gray] drawn in error_axes (end=(30.0, 0.0), dashed=True)","zero_result":"a Math [text] that says \"$e_infinity = 0$\""},"beats":[{"start":371.3833333333333,"say":"Proportional control reacts to the error right now, and right now is exactly what strands it. It has no way of knowing that this same small error has been sitting there, unfixed, for the last ten seconds. What it needs is a record.","live":[],"does":[[371.3833333333333,"heading is shown on the screen, written out."],[385.6753333333333,"concept is shown on the screen, written out."]]},{"start":387.0878333333333,"say":"So here is the error from that last run, plotted on its own. It starts at forty, falls fast while the correction is big, flattens out at ten, and sits there until fifteen seconds. Then the hill makes the error jump and settle higher.","live":["concept","heading"],"does":[[387.6913333333333,"error_axes is shown on the screen, written out."],[387.6913333333333,"zero_line is shown on the screen, written out."],[389.9903333333333,"error_curve is shown on the screen, drawn."],[398.2103333333333,"error_hill_line is shown on the screen, written out."],[400.3693333333333,"point is shown on the screen, grown."],[402.3693333333333,"point is hidden from the screen."]]},{"start":403.4538333333333,"say":"One thing to keep straight: this is the error, not the speed. Zero on this axis means the car is exactly on target, and every kilometre of gap up here is a kilometre the controller has failed to close.","live":["concept","error_axes","heading","zero_line","error_curve","error_hill_line"],"does":[[408.66633333333334,"zero_line is indicated — a transient flash."],[409.37533333333334,"The y axis of error_axes is lit up."],[413.3573333333333,"point_2 is shown on the screen, grown."],[415.3573333333333,"point_2 is hidden from the screen."]]},{"start":417.97433333333333,"say":"Now, instead of reading the height of this curve, add it up. Every second that goes by with an error of ten piles ten more onto the total. That accumulation is the area underneath the curve, from the moment we switched on up to now.","live":null,"does":[[429.1553333333333,"pile is shown on the screen, written out."],[429.1553333333333,"elapsed ticks to 6.0."],[430.6553333333333,"pile is redrawn as the numbers it depends on change."]]},{"start":433.7258333333333,"say":"And watch what that pile does while the error is stuck. It grows, and it keeps growing, and nothing ever takes anything off it. A leftover error that proportional control is perfectly happy with turns into an accumulation that gets bigger without limit.","live":["concept","error_axes","heading","zero_line","error_curve","error_hill_line","pile"],"does":[[437.6733333333333,"pile is redrawn as the numbers it depends on change."],[437.6733333333333,"elapsed ticks to 30.0."],[448.77233333333334,"pile is indicated — a transient flash."]]},{"start":450.6493333333333,"say":"So that is our second term. Add to the throttle a piece proportional to the accumulated error, the integral of e, with a gain of its own, K i.","live":null,"does":[[453.8763333333333,"law is shown on the screen, written out."],[457.5913333333333,"law becomes \"$u = K_p e + K_i integral_0^t e dif s$\"."],[459.1593333333333,"law (the \"K_i integral_0^t e dif s\" part) is emphasized."],[461.4228333333333,"law (the \"K_i integral_0^t e dif s\" part) is no longer emphasized."]]},{"start":462.0228333333333,"say":"And now ask where this controller can possibly come to rest. Suppose it settles with any error at all left over, even half a kilometre an hour. Then the integral keeps climbing, so the throttle keeps climbing, so the speed keeps climbing. It cannot be at rest.","live":["concept","law","error_axes","heading","zero_line","error_curve","error_hill_line","pile"],"does":[[471.72933333333333,"pile is indicated — a transient flash."],[472.1933333333333,"law (the \"K_i integral_0^t e dif s\" part) is emphasized."],[478.6023333333333,"law (the \"K_i integral_0^t e dif s\" part) is no longer emphasized."]]},{"start":479.20233333333334,"say":"The only value of the error it can hold still at is exactly zero. That is a strong claim, so let me put it plainly. A controller with an integral term, on a plant like this one, drives the steady error to zero. Not small. Not nearly. Zero.","live":null,"does":[[482.10433333333333,"zero_result is shown on the screen, written out."],[482.7203333333333,"zero_line is indicated — a transient flash."],[482.7203333333333,"zero_result (the \"0\" part) is emphasized."],[495.07283333333334,"law is hidden from the screen."],[495.07283333333334,"concept is hidden from the screen — left the board."],[495.07283333333334,"error_axes is hidden from the screen — left the board."],[495.07283333333334,"zero_line is hidden from the screen — error_axes left the board."],[495.07283333333334,"error_curve is hidden from the screen — error_axes left the board."],[495.07283333333334,"error_hill_line is hidden from the screen — error_axes left the board."],[495.07283333333334,"pile is hidden from the screen — error_axes left the board."],[495.07283333333334,"heading is hidden from the screen — left the board."],[495.07283333333334,"zero_result is hidden from the screen — left the board."],[495.07283333333334,"zero_result (the \"0\" part) is no longer emphasized."]]},{"start":496.2728333333333,"say":"So let's drive it. Grey is proportional alone, stuck at ninety. Green is the same proportional gain with the integral added, K i equal to one.","live":[],"does":[[496.2728333333333,"heading_two is shown on the screen, written out."],[496.9813333333333,"response_axes is shown on the screen, written out."],[496.9813333333333,"setpoint_line is shown on the screen, written out."],[496.9813333333333,"hill_line is shown on the screen, written out."],[497.9103333333333,"curve_p is shown on the screen, written out."],[500.7783333333333,"point_3 is shown on the screen, grown."],[501.9853333333333,"curve_pi is shown on the screen, drawn."],[502.7783333333333,"point_3 is hidden from the screen."],[504.4463333333333,"law is shown on the screen, written out."]]},{"start":508.52983333333333,"say":"It takes its time, because it has to build the pile up before the extra throttle amounts to anything. But it arrives. And it arrives exactly on the line, with no offset at all, which proportional control could not do at any gain.","live":["law","response_axes","heading_two","setpoint_line","hill_line","curve_p","curve_pi"],"does":[[517.6553333333334,"point_4 is shown on the screen, grown."],[518.7233333333334,"setpoint_line is indicated — a transient flash."],[519.6553333333334,"point_4 is hidden from the screen."]]},{"start":523.7933333333333,"say":"Then the hill hits. The speed sags, so the error comes back, so the pile starts growing again, and the controller walks the car back up to a hundred and holds it there.","live":null,"does":[[524.7453333333333,"hill_line is indicated — a transient flash."],[526.8233333333333,"point_5 is shown on the screen, grown."],[528.8233333333333,"point_5 is hidden from the screen."],[533.0473333333333,"point_6 is shown on the screen, grown."],[535.0473333333333,"point_6 is hidden from the screen."]]},{"start":535.4353333333333,"say":"That is the integral's whole job. It refuses to accept a leftover error, because a leftover error is a pile that never stops growing.","live":null,"does":[[536.7353333333333,"curve_pi is indicated — a transient flash."]]},{"start":544.6498333333333,"say":"But that memory costs you. Turn K i up to two and a half, and by the time the speed reaches the setpoint the accumulator has already commanded a large throttle. Being on target does not empty the pile. It only stops adding to it.","live":null,"does":[[544.6498333333333,"curve_p is hidden from the screen."],[548.4813333333333,"curve_pi_hot is shown on the screen, drawn."],[550.6873333333333,"point_7 is shown on the screen, grown."],[552.6873333333333,"point_7 is hidden from the screen."]]},{"start":559.8433333333332,"say":"So the car sails past, and the error has to go negative, the car has to spend time above the setpoint, before that accumulation comes back down. That is the overshoot and the ringing you are looking at.","live":["law","response_axes","heading_two","setpoint_line","hill_line","curve_pi","curve_pi_hot"],"does":[[560.7493333333333,"point_8 is shown on the screen, grown."],[562.7493333333333,"point_8 is hidden from the screen."],[562.9783333333332,"point_9 is shown on the screen, grown."],[564.9783333333332,"point_9 is hidden from the screen."],[570.4203333333332,"curve_pi_hot is indicated — a transient flash."]]},{"start":572.5523333333333,"say":"Taken to the extreme it has a name: integrator windup. If the throttle saturates, or the car is held back for a while, the accumulator keeps piling up error it cannot act on, and the plant spends the next several seconds paying it back.","live":null,"does":[[575.9073333333333,"windup is shown on the screen, written out."]]},{"start":588.4428333333333,"say":"So proportional gets us moving, integral finishes the job, and between them they have bought us an oscillation. The third term is the cure for that.","live":["law","windup","response_axes","heading_two","setpoint_line","hill_line","curve_pi","curve_pi_hot"],"does":[[598.38925,"heading_two is hidden from the screen — left the board."],[598.38925,"law is hidden from the screen — left the board."],[598.38925,"response_axes is hidden from the screen — left the board."],[598.38925,"setpoint_line is hidden from the screen — response_axes left the board."],[598.38925,"hill_line is hidden from the screen — response_axes left the board."],[598.38925,"curve_pi is hidden from the screen — response_axes left the board."],[598.38925,"curve_pi_hot is hidden from the screen — response_axes left the board."],[598.38925,"windup is hidden from the screen — left the board."]]}]},{"title":"Derivative Action","start":599.4309166666667,"end":813.0858541666666,"objects":{"caption":"a Tex [text] that says \"Both runs use $K_p = 6$ and $K_i = 3$. Only the green one has a derivative term.\"","caution":"a Panel that says \"The derivative of a measured signal amplifies measurement noise, so practical controllers filter it, or take it from the measurement rather than from the error.\"","concept":"a Panel that says \"Add a correction proportional to the rate of change of the error, so a fast approach is met with a brake before the target arrives. The constant $K_d$ is the derivative gain.\"","curve_pi":"a FunctionPlot [red] labelled \"K_d = 0\" drawn in response_axes (function=<function>)","curve_pid":"a FunctionPlot [green] labelled \"K_d = 3\" drawn in response_axes (function=<function>)","error_axes":"an Axes (x_range=(0.0, 30.0), y_range=(-20.0, 45.0), x_ticks_every=5.0)","error_curve":"a FunctionPlot [red] labelled \"e(t)\" drawn in error_axes (function=<function>)","heading":"a Heading that says \"Derivative: Watch Where the Error Is Going\"","heading_three":"a Heading that says \"The Whole Controller\"","heading_two":"a Heading that says \"The Same Gains, With and Without It\"","hill_line":"a Line [gray] drawn in response_axes (start=(15.0, 52.0), end=(15.0, 116.0), dashed=True)","law":"a Math [text] that says \"$u = K_p e + K_i integral_0^t e dif s$\"","point":"a Point [yellow] drawn in error_axes (location=(2.0, -14.63571006249039))","point_2":"a Point [yellow] drawn in response_axes (location=(2.35, 116.63155846479191))","point_3":"a Point [yellow] drawn in response_axes (location=(3.06, 110.35052006169673))","point_4":"a Point [yellow] drawn in response_axes (location=(6.0, 100.74774824076836))","point_5":"a Point [yellow] drawn in response_axes (location=(16.0, 96.88660775428984))","probe":"a VariableNumber (initial_value=2.0)","response_axes":"an Axes (x_range=(0.0, 30.0), y_range=(50.0, 120.0), x_ticks_every=5.0)","roles":"a Block [text] that says \"Proportional reacts to the present error. Integral reacts to the accumulated past. Derivative reacts to the error's direction of travel.\"","setpoint_line":"a Line [yellow] drawn in response_axes (start=(0.0, 100.0), end=(30.0, 100.0), dashed=True)","tangent":"a TangentLine [yellow] drawn in error_axes (target='error_curve', x=<VariableNumber probe = 30.0>, length=4.0)","term":"a Math [text] that says \"$K_d frac(dif e, dif t)$\"","zero_line":"a Line [gray] drawn in error_axes (end=(30.0, 0.0), dashed=True)"},"beats":[{"start":599.4309166666667,"say":"The trouble with that last run is that the controller only discovered it was going too fast after it had already gone too fast. Everything it knows is about the present and about the past. Nobody in there is looking ahead.","live":[],"does":[[599.4309166666667,"heading is shown on the screen, written out."],[600.2789166666666,"error_axes is shown on the screen, written out."],[600.2789166666666,"zero_line is shown on the screen, written out."],[602.9019166666667,"error_curve is shown on the screen, drawn."]]},{"start":612.8249166666667,"say":"But there is a look ahead sitting right in the data. Here is the error again, this time from an aggressive proportional plus integral tuning, the kind that rings. And at any instant we can ask a different question about it. Not how big is the error, but how fast is it changing.","live":["error_axes","heading","zero_line","error_curve"],"does":[[617.2829166666667,"error_curve is indicated — a transient flash."]]},{"start":630.7244166666667,"say":"That is the slope of this curve, and here it is at two seconds in. The error is still about twelve kilometres an hour, and it is falling at roughly twelve kilometres an hour each second. At that rate the car reaches the target in about one second.","live":null,"does":[[631.8039166666667,"tangent is shown on the screen, written out."],[633.8819166666667,"point is shown on the screen, grown."],[635.8819166666667,"point is hidden from the screen."],[638.6189166666667,"tangent is indicated — a transient flash."]]},{"start":646.0809166666667,"say":"And that number is a prediction. It is the controller's only honest statement about the future, and it costs nothing to compute, because it is right there in the measurement it already has.","live":["error_axes","heading","zero_line","error_curve","tangent"],"does":[[647.3229166666667,"tangent is indicated — a transient flash."]]},{"start":657.0834166666667,"say":"It is also the warning that proportional and integral cannot hear. Proportional sees a large error and pushes. The integral sees a large pile and pushes. Neither one knows that the correction already in the pipeline is more than enough.","live":null,"does":[[658.1979166666667,"error_axes moves to a new place on the board."],[658.1979166666667,"roles is shown on the screen, written out."],[658.8249166666667,"roles (the \"Proportional\" part) is emphasized."],[665.1989166666667,"roles (the \"Integral\" part) is emphasized."],[665.1989166666667,"roles (the \"Proportional\" part) is no longer emphasized."]]},{"start":672.7064166666667,"say":"So give the controller a third term. A piece proportional to the rate of change of the error, with a gain of its own, K d.","live":["roles","error_axes","heading","zero_line","error_curve","tangent"],"does":[[674.1689166666667,"term is shown on the screen, written out."],[674.1689166666667,"roles (the \"Derivative\" part) is emphasized."],[674.1689166666667,"roles (the \"Integral\" part) is no longer emphasized."],[678.3949166666667,"concept is shown on the screen, written out."],[680.3689166666667,"roles (the \"Derivative\" part) is no longer emphasized."]]},{"start":680.9689166666667,"say":"And read the sign carefully, because the sign is the whole idea. When the error is falling, d e by d t is negative, so this term subtracts throttle. The faster you are closing in, the harder it eases off. It is a brake that comes on only when you are approaching quickly.","live":["roles","concept","term","error_axes","heading","zero_line","error_curve","tangent"],"does":[[689.0149166666667,"term (the \"frac(dif e, dif t)\" part) is emphasized."]]},{"start":700.9469166666668,"say":"Now watch it along the whole run. Every time the car swings toward the line, the slope is steep and the term leans against the motion. Every time it swings away, the sign flips and the term leans the other way. And once the swinging stops, the curve goes flat and the slope is zero.","live":null,"does":[[702.3629166666667,"tangent is redrawn as the numbers it depends on change."],[702.3629166666667,"probe ticks to 30.0."],[707.4709166666667,"term (the \"K_d\" part) is emphasized."],[707.4709166666667,"term (the \"frac(dif e, dif t)\" part) is no longer emphasized."],[714.3089166666667,"term (the \"K_d\" part) is no longer emphasized."]]},{"start":719.3784166666667,"say":"That last part matters. At steady state, derivative action is silent. It cannot fix an offset and it cannot cause one. It only ever speaks while things are changing.","live":null,"does":[[731.5224166666667,"concept is hidden from the screen — left the board."],[731.5224166666667,"error_axes is hidden from the screen — left the board."],[731.5224166666667,"zero_line is hidden from the screen — error_axes left the board."],[731.5224166666667,"error_curve is hidden from the screen — error_axes left the board."],[731.5224166666667,"tangent is hidden from the screen — error_axes left the board."],[731.5224166666667,"heading is hidden from the screen — left the board."],[731.5224166666667,"roles is hidden from the screen — left the board."],[731.5224166666667,"term is hidden from the screen — left the board."]]},{"start":732.7224166666667,"say":"So here is that same aggressive tuning, with it and without it. Red is proportional plus integral, the run we just took apart. Green is the same two gains with derivative added, K d equal to three.","live":[],"does":[[732.7224166666667,"heading_two is shown on the screen, written out."],[733.0939166666667,"response_axes is shown on the screen, written out."],[733.0939166666667,"setpoint_line is shown on the screen, written out."],[733.0939166666667,"hill_line is shown on the screen, written out."],[737.4249166666667,"curve_pi is shown on the screen, written out."],[742.5799166666667,"curve_pid is shown on the screen, drawn."],[746.7009166666667,"caption is shown on the screen, written out."]]},{"start":748.1484166666667,"say":"The two leave the line at the same speed, because early on the error is huge and the proportional term dominates both of them. But the peak overshoot falls from about seventeen kilometres an hour to about ten, the ringing shrinks, and the green curve is within one kilometre an hour of the setpoint by about six seconds.","live":["response_axes","caption","heading_two","setpoint_line","hill_line","curve_pi","curve_pid"],"does":[[757.8889166666667,"point_2 is shown on the screen, grown."],[759.6999166666667,"point_3 is shown on the screen, grown."],[759.8889166666667,"point_2 is hidden from the screen."],[761.6999166666667,"point_3 is hidden from the screen."],[765.8069166666667,"point_4 is shown on the screen, grown."]]},{"start":767.5684166666667,"say":"Same car, same integral, one extra term. And the hill gets the same treatment, a shallow dip instead of a plunge, because the moment the speed starts to fall the derivative term sees the slope and pushes back, before the error has had time to grow.","live":["response_axes","caption","heading_two","setpoint_line","hill_line","curve_pi","curve_pid","point_4"],"does":[[767.8069166666667,"point_4 is hidden from the screen."],[771.4229166666667,"hill_line is indicated — a transient flash."],[773.3149166666667,"point_5 is shown on the screen, grown."],[775.3149166666667,"point_5 is hidden from the screen."],[779.0159166666667,"curve_pid is indicated — a transient flash."],[782.1739166666666,"caption is hidden from the screen — left the board."],[782.1739166666666,"heading_two is hidden from the screen — left the board."],[782.1739166666666,"response_axes is hidden from the screen — left the board."],[782.1739166666666,"setpoint_line is hidden from the screen — response_axes left the board."],[782.1739166666666,"hill_line is hidden from the screen — response_axes left the board."],[782.1739166666666,"curve_pi is hidden from the screen — response_axes left the board."],[782.1739166666666,"curve_pid is hidden from the screen — response_axes left the board."]]},{"start":783.3739166666667,"say":"So there is the whole controller. Three terms, one error signal. The present, the past, and the projected future, added up into a single number and sent to the throttle.","live":[],"does":[[783.3739166666667,"heading_three is shown on the screen, written out."],[786.7289166666667,"law is shown on the screen, written out."],[791.8029166666668,"law becomes \"$u = K_p e + K_i integral_0^t e dif s + K_d frac(dif e, dif t)$\"."]]},{"start":796.1529166666667,"say":"One caution before we tune it. That derivative is the slope of a measured signal, and real measurements are noisy. Differentiate noise and you amplify it, which is why practical controllers filter the derivative, or take it from the measurement rather than from the error.","live":["law","heading_three"],"does":[[796.7329166666667,"caution is shown on the screen, written out."],[812.0441875,"caution is hidden from the screen — left the board."],[812.0441875,"heading_three is hidden from the screen — left the board."],[812.0441875,"law is hidden from the screen — left the board."]]}]},{"title":"Tuning the Three Gains","start":813.0858541666666,"end":1001.8970416666666,"objects":{"applications":"a Block [text] that says \"Ovens hold temperature. Drones hold attitude. Disk drives hold position. Cruise control holds speed.\"","axes":"an Axes (x_range=(0.0, 30.0), y_range=(50.0, 120.0), x_ticks_every=5.0)","curve_good":"a FunctionPlot [green] labelled \"K_p = 6, K_i = 3, K_d = 3\" drawn in axes (function=<function>)","curve_hot_d":"a FunctionPlot [blue] labelled \"K_d = 15\" drawn in axes (function=<function>)","curve_hot_i":"a FunctionPlot [magenta] labelled \"K_i = 7\" drawn in axes (function=<function>)","curve_hot_p":"a FunctionPlot [red] labelled \"K_p = 18\" drawn in axes (function=<function>)","heading":"a Heading that says \"Three Gains, One Trade\"","heading_curve":"a Heading that says \"One Gain at a Time\"","heading_trade":"a Heading that says \"What Too Much Gain Does\"","heading_two":"a Heading that says \"Where PID Works\"","hill_line":"a Line [gray] drawn in axes (start=(15.0, 52.0), end=(15.0, 116.0), dashed=True)","methods":"a Block [text] that says \"Ziegler and Nichols: use sustained oscillation to set a starting point. Relay tuning: excite a controlled cycle and estimate the plant response.\"","pid_summary":"a Text [text] that says \"One error signal is read as present, accumulated past, and direction of travel.\"","point":"a Point [yellow] drawn in axes (location=(6.0, 100.74774824076836))","point_2":"a Point [yellow] drawn in axes (location=(1.0, 81.37159628279002))","point_3":"a Point [yellow] drawn in axes (location=(4.0, 107.7876990608755))","point_4":"a Point [yellow] drawn in axes (location=(20.0, 100.17060465631636))","roles":"a Block [text] that says \"Proportional reads the present error and sets the main response speed. Integral reads the accumulated past and removes steady error. Derivative reads the direction of travel and adds damping.\"","setpoint_line":"a Line [yellow] drawn in axes (start=(0.0, 100.0), end=(30.0, 100.0), dashed=True)","trade":"a Table [text] that says \"Gain pushed too high Visible cost $K_p$ More overshoot and faster ringing $K_i$ More overshoot and slower ringing $K_d$ Slower rise and more noise sensitivity\" (rows=(('Gain pushed too high', 'Visible cost'), ('$K_p$', 'More over…, header=True)"},"beats":[{"start":813.0858541666666,"say":"So. Three gains, and one system that has to rise quickly, settle cleanly, and hold. Tuning is nothing more than deciding how much of each of the three answers you want.","live":[],"does":[[813.0858541666666,"heading is shown on the screen, written out."]]},{"start":825.3888541666666,"say":"Proportional is the present. It reacts to the error you have right now, it is your main lever on how quickly you respond, and on its own it always leaves a gap.","live":["heading"],"does":[[826.7358541666666,"roles is shown on the screen, written out."],[826.7358541666666,"roles (the \"Proportional reads the present error and sets the main response speed.\" part) is emphasized."],[836.1388541666666,"roles (the \"Proportional reads the present error and sets the main response speed.\" part) is no longer emphasized."]]},{"start":836.7388541666667,"say":"Integral is the past. It accumulates what proportional keeps leaving behind, and it is the only one of the three that can drive the steady error to zero. It buys you accuracy, and it costs you overshoot.","live":["roles","heading"],"does":[[838.1788541666666,"roles (the \"Integral reads the accumulated past and removes steady error.\" part) is emphasized."],[850.1248541666666,"roles (the \"Integral reads the accumulated past and removes steady error.\" part) is no longer emphasized."]]},{"start":850.7248541666667,"say":"Derivative is the future. It reads the slope and leans against fast change. It buys you damping, and it costs you sensitivity to noise.","live":null,"does":[[851.9328541666666,"roles (the \"Derivative reads the direction of travel and adds damping.\" part) is emphasized."],[860.3493541666667,"roles moves to a new place on the board."],[860.3493541666667,"heading is hidden from the screen — left the board."],[860.3493541666667,"roles (the \"Derivative reads the direction of travel and adds damping.\" part) is no longer emphasized."]]},{"start":860.9493541666667,"say":"Here is the tuning we ended on. K p six, K i three, K d three. Quick off the line, one small overshoot, settled inside about six seconds, and it takes the hill in its stride.","live":["roles"],"does":[[860.9493541666667,"heading_curve is shown on the screen, written out."],[861.2978541666666,"axes is shown on the screen, written out."],[861.2978541666666,"setpoint_line is shown on the screen, written out."],[861.2978541666666,"hill_line is shown on the screen, written out."],[864.0038541666667,"curve_good is shown on the screen, drawn."],[871.2248541666667,"point is shown on the screen, grown."],[872.9318541666667,"curve_good is indicated — a transient flash."],[873.2248541666667,"point is hidden from the screen."]]},{"start":874.8668541666666,"say":"And watch which term is doing the work along that curve. In the first second it is nearly all proportional. Through the middle of the rise, derivative is holding it back. And after the hill, the last few kilometres an hour are closed by the integral, slowly, with the other two almost silent.","live":["roles","axes","heading_curve","setpoint_line","hill_line","curve_good"],"does":[[878.6748541666666,"point_2 is shown on the screen, grown."],[878.6748541666666,"roles (the \"Proportional reads the present error and sets the main response speed.\" part) is emphasized."],[880.6748541666666,"point_2 is hidden from the screen."],[881.9718541666666,"point_3 is shown on the screen, grown."],[881.9718541666666,"roles (the \"Derivative reads the direction of travel and adds damping.\" part) is emphasized."],[881.9718541666666,"roles (the \"Proportional reads the present error and sets the main response speed.\" part) is no longer emphasized."],[883.9718541666666,"point_3 is hidden from the screen."],[885.2228541666666,"point_4 is shown on the screen, grown."],[885.2228541666666,"roles (the \"Derivative reads the direction of travel and adds damping.\" part) is no longer emphasized."],[885.2228541666666,"roles (the \"Integral reads the accumulated past and removes steady error.\" part) is emphasized."],[887.2228541666666,"point_4 is hidden from the screen."],[893.2918541666667,"roles (the \"Integral reads the accumulated past and removes steady error.\" part) is no longer emphasized."]]},{"start":893.8918541666667,"say":"Now let's break it, one gain at a time, and watch the same curve move. Triple the proportional gain and the response gets snappy and impatient. It hits harder, it swings wider, and it argues with itself for a good deal longer before it settles.","live":null,"does":[[899.2678541666667,"curve_hot_p is shown on the screen, drawn."],[904.8398541666667,"curve_hot_p is indicated — a transient flash."]]},{"start":910.4788541666667,"say":"Put that back, and turn the integral up instead. The accumulator gets ahead of the plant, so the overshoot grows, and there is a long slow ring while the pile is paid back down.","live":["roles","axes","heading_curve","setpoint_line","hill_line","curve_good","curve_hot_p"],"does":[[910.9548541666667,"curve_hot_p is hidden from the screen."],[912.6038541666667,"curve_hot_i is shown on the screen, drawn."],[919.1168541666666,"curve_hot_i is indicated — a transient flash."]]},{"start":922.7703541666666,"say":"And too much derivative goes the other way. It is so eager to lean against any change at all that it drags its feet, and the rise slows right down. In a real plant it would also be turning every twitch of sensor noise into a twitch of the throttle.","live":["roles","axes","heading_curve","setpoint_line","hill_line","curve_good","curve_hot_i"],"does":[[922.7703541666666,"curve_hot_i is hidden from the screen."],[923.7458541666666,"curve_hot_d is shown on the screen, drawn."],[930.3398541666667,"curve_hot_d is indicated — a transient flash."],[938.0713541666667,"axes is hidden from the screen — left the board."],[938.0713541666667,"setpoint_line is hidden from the screen — axes left the board."],[938.0713541666667,"hill_line is hidden from the screen — axes left the board."],[938.0713541666667,"curve_good is hidden from the screen — axes left the board."],[938.0713541666667,"curve_hot_d is hidden from the screen — axes left the board."],[938.0713541666667,"heading_curve is hidden from the screen — left the board."],[938.0713541666667,"roles is hidden from the screen — left the board."]]},{"start":938.6713541666667,"say":"The three broken tunings make the trade explicit. Too much proportional gain buys speed with overshoot and fast ringing. Too much integral gain buys persistence with overshoot and slow ringing. Too much derivative gain buys resistance to change with a slower rise and greater noise sensitivity.","live":[],"does":[[938.6713541666667,"heading_trade is shown on the screen, written out."],[938.6713541666667,"trade is shown on the screen, written out."],[943.0138541666666,"trade is shown on the screen, written out."],[945.7658541666666,"trade is indicated — a transient flash."],[947.7738541666666,"trade is shown on the screen, written out."],[950.4328541666666,"trade is indicated — a transient flash."],[952.6038541666667,"trade is shown on the screen, written out."],[956.9808541666666,"trade is indicated — a transient flash."]]},{"start":958.9863541666666,"say":"Which is also why tuning rules exist. Ziegler and Nichols, relay tuning, and the rest of them are recipes for finding a decent corner of that trade without walking the whole space by hand.","live":["heading_trade"],"does":[[960.2868541666667,"methods is shown on the screen, written out."],[962.3178541666666,"methods (the \"Ziegler and Nichols: use sustained oscillation to set a starting point.\" part) is emphasized."],[963.9668541666666,"methods (the \"Relay tuning: excite a controlled cycle and estimate the plant response.\" part) is emphasized."],[963.9668541666666,"methods (the \"Ziegler and Nichols: use sustained oscillation to set a starting point.\" part) is no longer emphasized."],[971.4208541666667,"heading_trade is hidden from the screen — left the board."],[971.4208541666667,"methods is hidden from the screen — left the board."],[971.4208541666667,"trade is hidden from the screen — left the board."],[971.4208541666667,"methods (the \"Relay tuning: excite a controlled cycle and estimate the plant response.\" part) is no longer emphasized."]]},{"start":972.6208541666666,"say":"So that is P I D. One error signal, read three ways. What it is, what it has been, and where it is going. Multiply each reading by a gain, add them up, and send the sum to the actuator.","live":[],"does":[[972.6208541666666,"heading_two is shown on the screen, written out."],[974.8608541666666,"pid_summary is shown on the screen, written out."]]},{"start":987.1293541666666,"say":"It is a strikingly small idea, and it runs a startling fraction of the machines around you. The ovens, the drones, the disk drives, the cruise control in the car you came here in. Three terms. One error.","live":["pid_summary","heading_two"],"does":[[987.1293541666666,"applications is shown on the screen, written out."],[993.0268541666666,"applications (the \"Ovens hold temperature.\" part) is emphasized."],[993.6428541666666,"applications (the \"Drones hold attitude.\" part) is emphasized."],[993.6428541666666,"applications (the \"Ovens hold temperature.\" part) is no longer emphasized."],[994.5478541666666,"applications (the \"Disk drives hold position.\" part) is emphasized."],[994.5478541666666,"applications (the \"Drones hold attitude.\" part) is no longer emphasized."],[995.7668541666666,"applications (the \"Cruise control holds speed.\" part) is emphasized."],[995.7668541666666,"applications (the \"Disk drives hold position.\" part) is no longer emphasized."],[1000.605375,"applications (the \"Cruise control holds speed.\" part) is no longer emphasized."],[1000.855375,"applications is hidden from the screen — left the board."],[1000.855375,"heading_two is hidden from the screen — left the board."],[1000.855375,"pid_summary is hidden from the screen — left the board."]]}]}]},"durationSeconds":1002,"chapters":[{"title":"Holding a Setpoint","startSeconds":0,"narration":"Every machine that has to hold something steady is solving the same problem. A cruise control holding a speed. A thermostat holding a room temperature. The world knocks it off target, and it has to push back, by exactly the right amount and no more. So here is the question this whole lecture answers. How does a machine hold a setpoint that the world keeps knocking it off? PID answers with three corrections: the present error, its accumulated past, and its direction of travel. Let's make it concrete. A car on a road, and a driver who sets the cruise control to one hundred kilometres an hour. Left alone with no extra throttle, this car rolls along at sixty. And it does not respond instantly. Ask for more throttle, and the engine takes about a second to deliver the extra pull, and the car takes a few seconds more to work that pull into speed. Every real plant has that lag, and it is the reason control is hard at all. That target has a name. It's the setpoint, r. What the car is actually doing at each instant we'll call v of t. And the whole job of a controller is to make v equal r, and then keep it there. Now, the naive fix. Guess the throttle. Find the setting that holds a hundred on flat road, push the pedal to exactly there, and leave it. And on flat road, it works. And then, fifteen seconds in, the road tilts up. The grade swallows part of the engine's pull, and the speed sags. The throttle does not move, because nothing in this machine is looking at the speed. It settles twenty kilometres an hour below target, and it stays there for good. And notice where the fault is. The machine is not wrong about the throttle. It is wrong because it has no idea what the speed is doing. Nothing measures the output, so nothing can react to it. That is the whole disease of an open loop. It guesses, and it never checks. So let's close the loop. Measure the speed, subtract it from the setpoint, and call that difference the error. The error is the only thing our controller gets to look at. So everything from here is one question. Given the error, what throttle should I command? That is u equals some function of e, and the rest of this lecture is filling that function in. There are three classic answers, and they stack. Proportional, which reacts to the error right now. Integral, which remembers the whole history of the error. And derivative, which watches where the error is heading."},{"title":"Proportional Action","startSeconds":163.50145833333332,"narration":"So, the first answer, and it is the one everybody invents for themselves. Look at the error right now, and push back in proportion to it. Big error, big correction. Small error, small correction. Nothing else. In symbols, that is u equals K p times e. One number to pick, the proportional gain, and that is the entire controller. So let's watch it drive. Same car, same hill at fifteen seconds. We start with the gain set to one: the moment we switch on, the error is forty, so the controller asks for forty units of throttle, and the car pulls away. Notice the shape it makes. It starts flat, because the engine has not delivered anything yet. Then it swings up hard while the error is big. And it flattens out as the error shrinks, because the correction shrinks with it. And then it stops. Eighty kilometres an hour. Twenty short of the setpoint, and it will sit there all day. The controller is running, the loop is closed, and the car is still twenty short. And this is not a bug you can tune away. It is arithmetic. This controller commands a throttle proportional to the error, so if the error ever reached zero, the command would be zero as well, and with no extra throttle the car falls straight back to sixty. Say that again, because it is the crux. The only way this controller can command throttle is to be wrong. Ask it to hold a hundred and it must run below a hundred, permanently, to have any error left to work with. So the error cannot reach zero. It stops where the throttle it produces is exactly the throttle the car needs. Solve for that point and you get this. The error left over is the whole forty kilometre gap, divided by one plus the gain. Which tells you exactly what raising the gain buys. Turn it up to three, and the leftover error is ten. The car holds ninety, and it gets there quicker. Turn it up to nine and the error is down to four. But look what has happened to the shape. It arrives fast, sails past the setpoint, and takes a couple of swings to settle. And notice why that overshoot appeared at all. The engine's pull lags behind the command. By the time the car is on target there is still a large pull in the pipeline, and that surplus carries it straight past the line. Push on to fifteen and the ringing is worse again, while the offset has only crept from four down to two and a half. You can chase that gap as far as your patience for overshoot allows. You never reach zero. And now the hill, which is the same story told louder. Every one of these curves drops when the grade hits, and every one settles at a new, lower speed. With the gain at three the car held ninety on the flat. On the hill it holds eighty five. Same controller, same gain, twice the error. A bigger load needs a bigger throttle, and the only way this controller can command a bigger throttle is to be further from the setpoint. It is paid in error. So proportional control is fast, it is simple, and it is structurally incapable of finishing the job. To kill that last gap, the controller needs something proportional can never have. It needs a memory."},{"title":"Integral Action","startSeconds":371.3833333333333,"narration":"Proportional control reacts to the error right now, and right now is exactly what strands it. It has no way of knowing that this same small error has been sitting there, unfixed, for the last ten seconds. What it needs is a record. So here is the error from that last run, plotted on its own. It starts at forty, falls fast while the correction is big, flattens out at ten, and sits there until fifteen seconds. Then the hill makes the error jump and settle higher. One thing to keep straight: this is the error, not the speed. Zero on this axis means the car is exactly on target, and every kilometre of gap up here is a kilometre the controller has failed to close. Now, instead of reading the height of this curve, add it up. Every second that goes by with an error of ten piles ten more onto the total. That accumulation is the area underneath the curve, from the moment we switched on up to now. And watch what that pile does while the error is stuck. It grows, and it keeps growing, and nothing ever takes anything off it. A leftover error that proportional control is perfectly happy with turns into an accumulation that gets bigger without limit. So that is our second term. Add to the throttle a piece proportional to the accumulated error, the integral of e, with a gain of its own, K i. And now ask where this controller can possibly come to rest. Suppose it settles with any error at all left over, even half a kilometre an hour. Then the integral keeps climbing, so the throttle keeps climbing, so the speed keeps climbing. It cannot be at rest. The only value of the error it can hold still at is exactly zero. That is a strong claim, so let me put it plainly. A controller with an integral term, on a plant like this one, drives the steady error to zero. Not small. Not nearly. Zero. So let's drive it. Grey is proportional alone, stuck at ninety. Green is the same proportional gain with the integral added, K i equal to one. It takes its time, because it has to build the pile up before the extra throttle amounts to anything. But it arrives. And it arrives exactly on the line, with no offset at all, which proportional control could not do at any gain. Then the hill hits. The speed sags, so the error comes back, so the pile starts growing again, and the controller walks the car back up to a hundred and holds it there. That is the integral's whole job. It refuses to accept a leftover error, because a leftover error is a pile that never stops growing. But that memory costs you. Turn K i up to two and a half, and by the time the speed reaches the setpoint the accumulator has already commanded a large throttle. Being on target does not empty the pile. It only stops adding to it. So the car sails past, and the error has to go negative, the car has to spend time above the setpoint, before that accumulation comes back down. That is the overshoot and the ringing you are looking at. Taken to the extreme it has a name: integrator windup. If the throttle saturates, or the car is held back for a while, the accumulator keeps piling up error it cannot act on, and the plant spends the next several seconds paying it back. So proportional gets us moving, integral finishes the job, and between them they have bought us an oscillation. The third term is the cure for that."},{"title":"Derivative Action","startSeconds":599.4309166666667,"narration":"The trouble with that last run is that the controller only discovered it was going too fast after it had already gone too fast. Everything it knows is about the present and about the past. Nobody in there is looking ahead. But there is a look ahead sitting right in the data. Here is the error again, this time from an aggressive proportional plus integral tuning, the kind that rings. And at any instant we can ask a different question about it. Not how big is the error, but how fast is it changing. That is the slope of this curve, and here it is at two seconds in. The error is still about twelve kilometres an hour, and it is falling at roughly twelve kilometres an hour each second. At that rate the car reaches the target in about one second. And that number is a prediction. It is the controller's only honest statement about the future, and it costs nothing to compute, because it is right there in the measurement it already has. It is also the warning that proportional and integral cannot hear. Proportional sees a large error and pushes. The integral sees a large pile and pushes. Neither one knows that the correction already in the pipeline is more than enough. So give the controller a third term. A piece proportional to the rate of change of the error, with a gain of its own, K d. And read the sign carefully, because the sign is the whole idea. When the error is falling, d e by d t is negative, so this term subtracts throttle. The faster you are closing in, the harder it eases off. It is a brake that comes on only when you are approaching quickly. Now watch it along the whole run. Every time the car swings toward the line, the slope is steep and the term leans against the motion. Every time it swings away, the sign flips and the term leans the other way. And once the swinging stops, the curve goes flat and the slope is zero. That last part matters. At steady state, derivative action is silent. It cannot fix an offset and it cannot cause one. It only ever speaks while things are changing. So here is that same aggressive tuning, with it and without it. Red is proportional plus integral, the run we just took apart. Green is the same two gains with derivative added, K d equal to three. The two leave the line at the same speed, because early on the error is huge and the proportional term dominates both of them. But the peak overshoot falls from about seventeen kilometres an hour to about ten, the ringing shrinks, and the green curve is within one kilometre an hour of the setpoint by about six seconds. Same car, same integral, one extra term. And the hill gets the same treatment, a shallow dip instead of a plunge, because the moment the speed starts to fall the derivative term sees the slope and pushes back, before the error has had time to grow. So there is the whole controller. Three terms, one error signal. The present, the past, and the projected future, added up into a single number and sent to the throttle. One caution before we tune it. That derivative is the slope of a measured signal, and real measurements are noisy. Differentiate noise and you amplify it, which is why practical controllers filter the derivative, or take it from the measurement rather than from the error."},{"title":"Tuning the Three Gains","startSeconds":813.0858541666666,"narration":"So. Three gains, and one system that has to rise quickly, settle cleanly, and hold. Tuning is nothing more than deciding how much of each of the three answers you want. Proportional is the present. It reacts to the error you have right now, it is your main lever on how quickly you respond, and on its own it always leaves a gap. Integral is the past. It accumulates what proportional keeps leaving behind, and it is the only one of the three that can drive the steady error to zero. It buys you accuracy, and it costs you overshoot. Derivative is the future. It reads the slope and leans against fast change. It buys you damping, and it costs you sensitivity to noise. Here is the tuning we ended on. K p six, K i three, K d three. Quick off the line, one small overshoot, settled inside about six seconds, and it takes the hill in its stride. And watch which term is doing the work along that curve. In the first second it is nearly all proportional. Through the middle of the rise, derivative is holding it back. And after the hill, the last few kilometres an hour are closed by the integral, slowly, with the other two almost silent. Now let's break it, one gain at a time, and watch the same curve move. Triple the proportional gain and the response gets snappy and impatient. It hits harder, it swings wider, and it argues with itself for a good deal longer before it settles. Put that back, and turn the integral up instead. The accumulator gets ahead of the plant, so the overshoot grows, and there is a long slow ring while the pile is paid back down. And too much derivative goes the other way. It is so eager to lean against any change at all that it drags its feet, and the rise slows right down. In a real plant it would also be turning every twitch of sensor noise into a twitch of the throttle. The three broken tunings make the trade explicit. Too much proportional gain buys speed with overshoot and fast ringing. Too much integral gain buys persistence with overshoot and slow ringing. Too much derivative gain buys resistance to change with a slower rise and greater noise sensitivity. Which is also why tuning rules exist. Ziegler and Nichols, relay tuning, and the rest of them are recipes for finding a decent corner of that trade without walking the whole space by hand. So that is P I D. One error signal, read three ways. What it is, what it has been, and where it is going. Multiply each reading by a gain, add them up, and send the sum to the actuator. It is a strikingly small idea, and it runs a startling fraction of the machines around you. The ovens, the drones, the disk drives, the cruise control in the car you came here in. Three terms. One error."}]}}
