I have a program being ran every 20 milliseconds and I'm trying to implement PID control. So P = SetPoint - Actual, I = I + P ? , and D = P - Old_P???? On D, should "Old_P" be from the previous round or should it be a value from a certain length of time ago? Also, is "I" just summed up or is it the sum of I over a certain length of time? I'm trying to find out if I need to set up arrays to accumulate 50 samples per second of time for setting I and D values. Also, are Kp, Ki, and Kd just multipliers? I can calculate a value for I and D each scan to scan but it seems like it could be more stable if I use a time period that fights the process's oscillation period. RogerN

# PID Control programming Questions

Started by ●September 27, 2013

Reply by ●September 27, 20132013-09-27

On 9/27/2013 8:19 PM, RogerN wrote:> I have a program being ran every 20 milliseconds and I'm trying to implement > PID control. So P = SetPoint - Actual, I = I + P ? , and D = P - Old_P???? > On D, should "Old_P" be from the previous round or should it be a value > from a certain length of time ago? Also, is "I" just summed up or is it the > sum of I over a certain length of time? > > I'm trying to find out if I need to set up arrays to accumulate 50 samples > per second of time for setting I and D values. Also, are Kp, Ki, and Kd > just multipliers? I can calculate a value for I and D each scan to scan but > it seems like it could be more stable if I use a time period that fights the > process's oscillation period. > > RogerNIf you want the control system to be approximately linear and time invariant, you need to keep the sampling period consistent. The real control system guys will chime in, hopefully, but one thing to watch is that if the time step gets too coarse with respect to the system bandwidth, your loop's performance will diverge more and more from the continuous-time case. Cheers Phil Hobbs -- Dr Philip C D Hobbs Principal Consultant ElectroOptical Innovations LLC Optics, Electro-optics, Photonics, Analog Electronics 160 North State Road #203 Briarcliff Manor NY 10510 USA +1 845 480 2058 hobbs at electrooptical dot net http://electrooptical.net

Reply by ●September 27, 20132013-09-27

On Friday, September 27, 2013 8:19:53 PM UTC-4, RogerN wrote:> I have a program being ran every 20 milliseconds and I'm trying to implem=ent=20>=20 > PID control. =20 > RogerNI am not a control person, but I am pretty sure you do not need 50 samples. PID stands for Proportional, Integral, and Differential. Start with Propor= tional. You have the value desired and the actual value. The difference = between the two is the error signal. So the proportional part is just the = error signal times some amount. Next is the differential. This is just th= e first derivative. That is to say is the error signal decreasing or incre= asing. If the error signal is decreasing, you reduce the error signal a bi= t depending on how fast the error signal is decreasing. If the error signa= l is increasing, you increase the error signal. this helps the system to s= ettle down and not overshoot. Last is the Integral. This is just a runnin= g sum of the error signal. So if the system is always a bit low, you add i= n some signal to raise it up.It gets rid of constant errors. In tuning a s= ystem you start with just the proportional signal, Then add in some differe= ntial to improve system response and reduce overshooting. And finally if t= he system has some constant error, you add in some integral. As I see it you only need one sample for the Proportional part. Two sample= s for the differential part , and one sample plus a running sum for the int= egral part. Mind you I have never implemented a digital PID system, so if anyone else c= hims in, they are probably right and I am out in left field. Dan

Reply by ●September 27, 20132013-09-27

Hi Roger, On 9/27/2013 5:19 PM, RogerN wrote:> I have a program being ran every 20 milliseconds and I'm trying to implement > PID control. So P = SetPoint - Actual, I = I + P ? , and D = P - Old_P???? > On D, should "Old_P" be from the previous round or should it be a value > from a certain length of time ago? Also, is "I" just summed up or is it the > sum of I over a certain length of time?(sigh) This is one of those things where (it appears) you really should do a bit more homework. There are lots of subtleties in implementing control systems -- even using "classic" algorithms. To answer your question (illustration, only): error = set_point - observed_value proportional_term = Kp * error integral_term = integral_term + Ki * error derivative_term = Kd * (observed_value - old_value) output = proportional_term + integral_term + derivative_term old_value = observed_value lather, rinse, repeat There are *lots* of equivalent ways of rewriting this. But, they have subtle differences in the implementation. For example, you could invert the sign of error. Or, you could implement the integrator as: accumulator += error integral_term = Ki * accumulator Many controllers put limits on the various terms. Or, introduce a deadband (i.e., so small "error" values are treated as '0'). What you have to look at is how changes to your control parameters affect the instantaneous output of the controller. Note that changing the set point *looks* like a change in the error term (as far as the math is concerned). Similarly, changing a gain has an instantaneous effect on the output. Consider how changing Ki affects the two different forms of integral_term implementations, above! Once you add an integral term, you open the door for oscillations. Not surprisingly, there are lots of mechanisms that try to control this. E.g., anti-windup prevents the "accumulator" from growing *so* big that it dominates the control (and leads to oscillation). Bumpless-transfer tries to "zero" the controller when first engaged (setpoint changes, etc.) Some algorithms will clear the "accumulator" whenever the error changes sign. At all times, you want to be sure you aren't asking your controller to do more than is possible (i.e., if the output is "at its limits", AT ANY INSTANT then the loop is probably in trouble). You also want to be sure you are sampling the system at a much higher rate than it's inherent bandwidth. And, that there is little jitter (variation) in your sample to sample time intervals. Also, that you are measuring the process with sufficient resolution that you can actually discern the difference between values (if you have poor resolution, the controller can oscillate between two "corrections" that correspond to X and X+epsilon)> I'm trying to find out if I need to set up arrays to accumulate 50 samples > per second of time for setting I and D values.No.> Also, are Kp, Ki, and Kd just multipliers?Yes. "Gains"> I can calculate a value for I and D each scan to scan but > it seems like it could be more stable if I use a time period that fights the > process's oscillation period.'I' and 'D' vary as functions of the error (and accumulated error). [(sigh) looking back over this, its just too many random notes, poorly organized. Find a good introductory reference and spend an hour looking at what each term *tries* to do so you can see how they can work in your favor -- as well as against you!]

Reply by ●September 28, 20132013-09-28

On Fri, 27 Sep 2013 19:19:53 -0500, the renowned "RogerN" <regor@midwest.net> wrote:> >I have a program being ran every 20 milliseconds and I'm trying to implement >PID control. So P = SetPoint - Actual, I = I + P ? , and D = P - Old_P???? >On D, should "Old_P" be from the previous round or should it be a value >from a certain length of time ago? Also, is "I" just summed up or is it the >sum of I over a certain length of time? > >I'm trying to find out if I need to set up arrays to accumulate 50 samples >per second of time for setting I and D values. Also, are Kp, Ki, and Kd >just multipliers? I can calculate a value for I and D each scan to scan but >it seems like it could be more stable if I use a time period that fights the >process's oscillation period. > >RogerNThere are many ways to implement PID. Looks like you're trying to implement the simplest version of the "position" type. 1) You should scale the time constants by the sample time Ts so that they can be specified in seconds eg. Ki = Ts/Ti, Kd = Td/Ts for Ti integral time, Td derivative time. 2) It's common to filter the D term by something like 1/10 the D time.. you can use a simple IIR filter. Otherwise it tends to be useless or harmful because of noise. You can leave it out and see if it's actually required. 3) Whether you differentiate the error or the PV depends on the requirements, I've had to do both, depending on whether (and how!) the setpoint changes A simple discrete-time PID controller is something like.. SP = setpoint PV = process variable error = SP - PV Output = Kp * (error + Ki * sum_errors - Kd * (PV - last_PV)) + bias ^^^^^^^^^^^^ (oversimplified) The sum_errors is a sum forever- it should (if the controller is tuned properly, the system is cooperative, disturbances are minimal, and sufficient control authority is available) eventually settle down to a number such that it drives the controller output to the required steady-state value without error or derivative input contributions. When output hits the limits, at least stop summing the errors (digging the hole) because otherwise you'll have horrible "reset windup" over/undershoot and even oscillation. To try to answer your questions.. the integral is the sum of errors over time. There's no reason to filter it. Derivative is the problem child and you may wish to implement a filter. If your sample time is maybe 10x the process time constant, then you may not need to filter it, but usually it's much faster, and you'll want to add a filter (or not use the derivative term). A simple IIR low pass filter (first order lag) with time constant Tc seconds is m += Kf * (x - last_m) where Kf = Ts/(Ts + Tc) For example, if Ts = 0.02 and you want a 30 second time constant, Kf = 0.02/30.02 Obviously you'll need to initialize the sums in the filter and the integrator to something reasonable (like maybe zero) to begin with. An IIR filter intitialized to a random floating-point number might never get to anything sensible, and same with the integral term. BTW, in all cases we require that Ts is constant. It could actually be changed dynamically, as could the tuning, but that requires special considerations to deal with what happened in the past. Often you need to do more sophisticated things with the integral term, but that's beyond the scope of this discussion. Best regards, Spehro Pefhany -- "it's the network..." "The Journey is the reward" speff@interlog.com Info for manufacturers: http://www.trexon.com Embedded software/hardware/analog Info for designers: http://www.speff.com

Reply by ●September 28, 20132013-09-28

"RogerN" <regor@midwest.net> wrote in message news:RdWdnRfaTvUDvdvPnZ2dnUVZ_rCdnZ2d@earthlink.com...> > I have a program being ran every 20 milliseconds and I'm trying to > implement PID control. So P = SetPoint - Actual, I = I + P ? , and D = > P - Old_P???? On D, should "Old_P" be from the previous round or should > it be a value from a certain length of time ago? Also, is "I" just summed > up or is it the sum of I over a certain length of time? > > I'm trying to find out if I need to set up arrays to accumulate 50 samples > per second of time for setting I and D values. Also, are Kp, Ki, and Kd > just multipliers? I can calculate a value for I and D each scan to scan > but it seems like it could be more stable if I use a time period that > fights the process's oscillation period. > > RogerN >Implementing PID in an incremental form is useful, it makes switching on and off without bumps easier. The basic idea is this: Error = target value - measured value Delta_output = (Pterm + Iterm + Dterm) * Gain Pterm = Error - PreviousError Iterm = Error * SamplePeriod / Tintegral Dterm = post again if you want more info. Derivative has many variants. Depending on what you want to control, you may not need it, it's generally a pain and best avoided. This form is called 'interactive' because the gain applies to the composite control action, rather than just eg. the proportional. IMHO, this isn't worth fretting about. It's easiest if you normalise your input and output to standard ranges, maybe 0 - 100% or a 32 bit range. Digital implementations need to watch numeric precision. If the sampling rate is high, quantisation in the calcs can cause dead zones in the integral response, because if the error is below the calculation MSB, integral action ceases. HTH

Reply by ●September 28, 20132013-09-28

On Sat, 28 Sep 2013 21:33:25 +0800, the renowned "Bruce Varley" <bv@NoSpam.com> wrote:> >"RogerN" <regor@midwest.net> wrote in message >news:RdWdnRfaTvUDvdvPnZ2dnUVZ_rCdnZ2d@earthlink.com... >> >> I have a program being ran every 20 milliseconds and I'm trying to >> implement PID control. So P = SetPoint - Actual, I = I + P ? , and D = >> P - Old_P???? On D, should "Old_P" be from the previous round or should >> it be a value from a certain length of time ago? Also, is "I" just summed >> up or is it the sum of I over a certain length of time? >> >> I'm trying to find out if I need to set up arrays to accumulate 50 samples >> per second of time for setting I and D values. Also, are Kp, Ki, and Kd >> just multipliers? I can calculate a value for I and D each scan to scan >> but it seems like it could be more stable if I use a time period that >> fights the process's oscillation period. >> >> RogerN >> > >Implementing PID in an incremental form is useful, it makes switching on and >off without bumps easier. The basic idea is this:Note that this method effectively integrates at the output. It's also called the "velocity" algorithm (you could think of an output being the angular velocity of a control valve shaft)- the motor and valve acts as a mechanical integrator that stops when it hits a limit. As Bruce implies, it's not quite as easy, but not impossible to do bumpless auto-manual transfer etc. with the position algorithm, you just have to preload the integrator with a back-calculated value to avoid a bump. Challenging back in the analog/pneumatic days.>Error = target value - measured value > >Delta_output = (Pterm + Iterm + Dterm) * Gain > >Pterm = Error - PreviousError > >Iterm = Error * SamplePeriod / TintegralIf the integration of the output is done digitally, it has to be limited at the physical limits of the output or windup will occur.>Dterm = post again if you want more info. Derivative has many variants. >Depending on what you want to control, you may not need it, it's generally a >pain and best avoided.For this type of PID algorithm you have to estimate the _second_ derivative of the error or PV wrt time for the derivative function. It can be done- but noise is a practical problem.>This form is called 'interactive' because the gain applies to the composite >control action, rather than just eg. the proportional. IMHO, this isn't >worth fretting about.The interactive form with a derivative block is more different.>It's easiest if you normalise your input and output to standard ranges, >maybe 0 - 100% or a 32 bit range. > >Digital implementations need to watch numeric precision. If the sampling >rate is high, quantisation in the calcs can cause dead zones in the integral >response, because if the error is below the calculation MSB, integral action >ceases. HTHITYM "LSB". This is only a problem with badly scaled or poorly designed fixed-point calculations (and as Bruce says, very high sampling rate relative to the time constants of the system). The longest possible integration time constant divided into the sample time, multiplied by the a number less than the resolution/noise of the PV should not come out to zero in the calculation preceding integration (nor can it not change the integral number when added to it). If you're sampling 1000 times a second and using a 3600 second time constant, that's 2.78E-7. Not a problem with floating point and enough mantissa bits, but with fixed point it can't be allowed to fall off the end or you can get persistent errors proportional to the integration time setting (for a fixed sample time). This is one reason I write my own fixed point math library routines for fractional math with sensible radix point positions (and enough bits). Best regards, Spehro Pefhany -- "it's the network..." "The Journey is the reward" speff@interlog.com Info for manufacturers: http://www.trexon.com Embedded software/hardware/analog Info for designers: http://www.speff.com

Reply by ●September 28, 20132013-09-28

On Sat, 28 Sep 2013 16:24:06 -0400, Spehro Pefhany wrote:> On Sat, 28 Sep 2013 21:33:25 +0800, the renowned "Bruce Varley" > <bv@NoSpam.com> wrote: > > >>"RogerN" <regor@midwest.net> wrote in message >>news:RdWdnRfaTvUDvdvPnZ2dnUVZ_rCdnZ2d@earthlink.com... >>> >>> I have a program being ran every 20 milliseconds and I'm trying to >>> implement PID control. So P = SetPoint - Actual, I = I + P ? , and D >>> = >>> P - Old_P???? On D, should "Old_P" be from the previous round or >>> should it be a value from a certain length of time ago? Also, is "I" >>> just summed up or is it the sum of I over a certain length of time? >>> >>> I'm trying to find out if I need to set up arrays to accumulate 50 >>> samples per second of time for setting I and D values. Also, are Kp, >>> Ki, and Kd just multipliers? I can calculate a value for I and D each >>> scan to scan but it seems like it could be more stable if I use a time >>> period that fights the process's oscillation period. >>> >>> RogerN >>> >>> >>Implementing PID in an incremental form is useful, it makes switching on >>and off without bumps easier. The basic idea is this: > > Note that this method effectively integrates at the output. It's also > called the "velocity" algorithm (you could think of an output being the > angular velocity of a control valve shaft)- the motor and valve acts as > a mechanical integrator that stops when it hits a limit. As Bruce > implies, it's not quite as easy, but not impossible to do bumpless > auto-manual transfer etc. with the position algorithm, you just have to > preload the integrator with a back-calculated value to avoid a bump. > Challenging back in the analog/pneumatic days. > >>Error = target value - measured value >> >>Delta_output = (Pterm + Iterm + Dterm) * Gain >> >>Pterm = Error - PreviousError >> >>Iterm = Error * SamplePeriod / Tintegral > > If the integration of the output is done digitally, it has to be limited > at the physical limits of the output or windup will occur. > >>Dterm = post again if you want more info. Derivative has many variants. >>Depending on what you want to control, you may not need it, it's >>generally a pain and best avoided. > > For this type of PID algorithm you have to estimate the _second_ > derivative of the error or PV wrt time for the derivative function. It > can be done- but noise is a practical problem. > >>This form is called 'interactive' because the gain applies to the >>composite control action, rather than just eg. the proportional. IMHO, >>this isn't worth fretting about. > > The interactive form with a derivative block is more different. > >>It's easiest if you normalise your input and output to standard ranges, >>maybe 0 - 100% or a 32 bit range. >> >>Digital implementations need to watch numeric precision. If the sampling >>rate is high, quantisation in the calcs can cause dead zones in the >>integral response, because if the error is below the calculation MSB, >>integral action ceases. HTH > > ITYM "LSB". This is only a problem with badly scaled or poorly designed > fixed-point calculations (and as Bruce says, very high sampling rate > relative to the time constants of the system).This can also happen with poorly designed floating point implementations, particularly when the sampling rate is high with respect to the loop closure bandwidth, and you are using single-precision floating point.> The longest possible integration time constant divided into the sample > time, multiplied by the a number less than the resolution/noise of the > PV should not come out to zero in the calculation preceding integration > (nor can it not change the integral number when added to it).That's a very effective way of putting things, and it applies to floating point as well as fixed point math. The big difference between fixed and floating point is that with fixed point if it works at one integrator value it works at all, while with floating point the input required to affect the integrator grows as the integrator absolute value grows.> If you're > sampling 1000 times a second and using a 3600 second time constant, > that's 2.78E-7. Not a problem with floating point and enough mantissa > bits, but with fixed point it can't be allowed to fall off the end or > you can get persistent errors proportional to the integration time > setting (for a fixed sample time). This is one reason I write my own > fixed point math library routines for fractional math with sensible > radix point positions (and enough bits).Again, it can be a problem with floating point (as Spehro alludes to in his comment about mantissa bits). For most real systems it's never going to be a problem if you use double-precision floating point, but with single-precision floating point it crops up often as an issue. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com

Reply by ●September 28, 20132013-09-28

On Fri, 27 Sep 2013 19:40:07 -0700, Don Y wrote:> Hi Roger, > > On 9/27/2013 5:19 PM, RogerN wrote: >> I have a program being ran every 20 milliseconds and I'm trying to >> implement PID control. So P = SetPoint - Actual, I = I + P ? , and D = >> P - Old_P???? On D, should "Old_P" be from the previous round or >> should it be a value from a certain length of time ago? Also, is "I" >> just summed up or is it the sum of I over a certain length of time? > > (sigh) This is one of those things where (it appears) you really should > do a bit more homework. There are lots of subtleties in implementing > control systems -- even using "classic" algorithms. > > To answer your question (illustration, only): > error = set_point - observed_value proportional_term = Kp * error > integral_term = integral_term + Ki * error derivative_term = Kd * > (observed_value - old_value) > output = proportional_term + integral_term + derivative_term > old_value = observed_value > lather, rinse, repeat > > There are *lots* of equivalent ways of rewriting this. But, they have > subtle differences in the implementation. > > For example, you could invert the sign of error. Or, you could > implement the integrator as: > accumulator += error integral_term = Ki * accumulator > > Many controllers put limits on the various terms. Or, introduce a > deadband (i.e., so small "error" values are treated as '0'). > > What you have to look at is how changes to your control parameters > affect the instantaneous output of the controller. > > Note that changing the set point *looks* like a change in the error term > (as far as the math is concerned). > > Similarly, changing a gain has an instantaneous effect on the output. > Consider how changing Ki affects the two different forms of > integral_term implementations, above! > > Once you add an integral term, you open the door for oscillations. > > Not surprisingly, there are lots of mechanisms that try to control this. > E.g., anti-windup prevents the "accumulator" from growing *so* big that > it dominates the control (and leads to oscillation). Bumpless-transfer > tries to "zero" the controller when first engaged (setpoint changes, > etc.) Some algorithms will clear the "accumulator" > whenever the error changes sign. > > At all times, you want to be sure you aren't asking your controller to > do more than is possible (i.e., if the output is "at its limits", AT ANY > INSTANT then the loop is probably in trouble).I have not found this to be the case in practice. Particularly with motion control loops going from point A to point B, if you design your anti-windup logic correctly you can be at the rails at various spots in the trajectory and be fine. Even with fairly primitive anti-windup, you can often have the output at the rail for a small part of the trajectory without undue problems. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com

Reply by ●September 28, 20132013-09-28

On Fri, 27 Sep 2013 19:19:53 -0500, RogerN wrote:> I have a program being ran every 20 milliseconds and I'm trying to > implement PID control. So P = SetPoint - Actual, I = I + P ? , and D = > P - Old_P???? On D, should "Old_P" be from the previous round or should > it be a value from a certain length of time ago? Also, is "I" just > summed up or is it the sum of I over a certain length of time? > > I'm trying to find out if I need to set up arrays to accumulate 50 > samples per second of time for setting I and D values. Also, are Kp, > Ki, and Kd just multipliers? I can calculate a value for I and D each > scan to scan but it seems like it could be more stable if I use a time > period that fights the process's oscillation period. > > RogerNYou've gotten lots of good answers. Doing PID control "right" takes a lot of knowledge, but doing it "kinda right" is often more than enough and doesn't take a lot at all. Unfortunately, if you don't have much control smarts you don't always have the tools to know if "kinda right" is going to be good enough without giving it a whirl. Try reading this: http://www.embedded.com/design/prototyping-and-development/4211211/PID- without-a-PhD I'm going to have to put this up on my website: it seems like they're changing the link on a monthly basis these days. It kinda-sorta contradicts things that Bruce and Spehro said. That's because I'm 100% right and they're a couple of -- uh wait. That's because there's a lot of different ways to skin this particular cat. I hope my article helps. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com