Reply by Tim Wescott September 29, 20132013-09-29
On Sun, 29 Sep 2013 14:22:17 +0800, Bruce Varley wrote:

> "Tim Wescott" <tim@seemywebsite.please> wrote in message > news:UvydncxdEOV769rPnZ2dnUVZ_qydnZ2d@giganews.com... >> 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. >>> >>> RogerN >> >> You'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 > > Yes, that is indeed a good article. One point in it noted, and Tim is > quite correct, if you do use derivative it's good to derive it from the > measurement input rather than the error signal, so that you don't get > large output spikes when the setpoint is changed (often in steps). In > fact, it's sometimes good to have the *proportional* treated in this way > as well, so that when a target change is made, the controller ramps to > the new state at the integral time rate. Very applicable in process > plants to keep operators happy, not so good if you're working with > missile control.
Yes, I would have mentioned having the proportional run off of just the process output -- but I had a 5000 word limit, which I ran over and had to edit down to. I think that article had over 4900 words in it.
> Expanding a bit on derivative, industrial system algos generally used > what's referred to as 'filtered derivative'. It's derived by applying a > filter to the input (measurement or error as above), then subtracting > the filter output from the filter input. The result is then multiplied > by an arbitrary constant (typ 4 - 6) and this is the derivative term. It > has the advantage over classical forms that if there's an 'infinitely > fast' change in the input, the change in the output isn't 'infinitely' > great.
Also known as bandlimited derivative. I don't know if I mention it in the article -- I do in a related talk, but the talk has changed so many times over the years I couldn't say what's been said when. Using a "naked" derivative term in a controller that's being sampled significantly slower than the desired bandwidth can also cause high frequency oscillations. This is highly dependent on the plant, of course, but bandlimiting the derivative can allow you to use higher derivative gains and keep the system stable. Using a "naked" derivative term also causes problems if you have measurement noise -- noise is, by nature, broad-band, and derivative action, by nature, amplifies the high frequency. Put measurement noise and derivative together and you can get a control output that has so much noise that the desired control output is lost. All in all, derivative control is something best approached with caution, and the right tools. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com
Reply by Bruce Varley September 29, 20132013-09-29
"Tim Wescott" <tim@seemywebsite.please> wrote in message
news:UvydncxdEOV769rPnZ2dnUVZ_qydnZ2d@giganews.com...
> 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. >> >> RogerN > > You'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
Yes, that is indeed a good article. One point in it noted, and Tim is quite correct, if you do use derivative it's good to derive it from the measurement input rather than the error signal, so that you don't get large output spikes when the setpoint is changed (often in steps). In fact, it's sometimes good to have the *proportional* treated in this way as well, so that when a target change is made, the controller ramps to the new state at the integral time rate. Very applicable in process plants to keep operators happy, not so good if you're working with missile control. Expanding a bit on derivative, industrial system algos generally used what's referred to as 'filtered derivative'. It's derived by applying a filter to the input (measurement or error as above), then subtracting the filter output from the filter input. The result is then multiplied by an arbitrary constant (typ 4 - 6) and this is the derivative term. It has the advantage over classical forms that if there's an 'infinitely fast' change in the input, the change in the output isn't 'infinitely' great.
Reply by Spehro Pefhany September 28, 20132013-09-28
On Sat, 28 Sep 2013 19:34:21 -0500, the renowned Tim Wescott
<tim@seemywebsite.please> wrote:

>On Fri, 27 Sep 2013 19:40:07 -0700, Don Y wrote: > >> 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.
Sure, to expand on Tim's example, consider a temperature control loop. Normally the output will be at its limit for a considerable time during start-up. A badly implemented controller can overshoot like crazy, but the solution isn't to put a megawatt heater in there for something that requires a kW steady-state, it's to fix the controller-- meaning it's no longer a textbook PID, but has some barnacles such as Tim mentions below.
>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.
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 Tim Wescott 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. > > RogerN
You'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
Reply by Tim Wescott 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 Tim Wescott 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 Spehro Pefhany 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 / 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). 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 Bruce Varley 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 Spehro Pefhany 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. > >RogerN
There 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 Don Y 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!]