How to Reduce Oscillation in a PID Controller

Oscillation in a PID controller almost always comes down to gains that are too aggressive, a missing or underused derivative term, or noise in the feedback signal tricking the controller into overcorrecting. The fix depends on which of these is causing the problem, but the most common starting point is reducing your proportional gain and then systematically adjusting the other two terms.

Why PID Controllers Oscillate

A PID controller continuously calculates the error between your setpoint and the actual measured output, then applies three correction terms: proportional (P), integral (I), and derivative (D). Oscillation happens when the combined output of these terms overshoots the setpoint, then overcorrects in the opposite direction, creating a cycle. The proportional term reacts to the size of the current error, the integral term accumulates past error to eliminate steady-state offset, and the derivative term reacts to how fast the error is changing. If any of these is set too high relative to how your system actually responds, the controller pushes harder than the system can absorb, and you get oscillation.

There are also non-tuning causes. Sensor noise can inject false rapid changes into the error signal, which the derivative term amplifies into wild output swings. A slow or inconsistent loop update rate can cause the controller to act on stale data. And mechanical issues like backlash or friction can make the system respond unpredictably, which no amount of tuning will fully fix.

Adjust Your Gains Step by Step

The most reliable manual tuning approach follows a specific order: start with all three gains at zero, then build up one at a time.

  • Set Kp, Ki, and Kd to zero. This gives you a clean baseline.
  • Increase Kp until steady-state error is small. The proportional term alone can never fully eliminate error (it needs a nonzero error to produce any output), but it should get you close to your setpoint. If you see oscillation at this stage, your Kp is already too high.
  • Increase Ki to remove the remaining steady-state error. The integral term accumulates error over time and pushes the output toward zero offset. Add it slowly, because too much integral gain is one of the most common causes of slow, sweeping oscillations.
  • Increase Kd to dampen oscillations. The derivative term resists rapid changes in error, acting as a brake when the system is moving toward or away from the setpoint too quickly. This is what smooths out the overshoot and ringing that P and I introduce.

If you’re already running a tuned controller that started oscillating, work backward. First try reducing Kp by 10 to 20 percent and observe. Then reduce Ki. These two are the most common culprits. Only touch Kd if the oscillations are high-frequency and jerky rather than slow and sweeping.

Use the Ziegler-Nichols Method

If manual trial-and-error isn’t converging, the Ziegler-Nichols closed-loop method gives you a structured starting point. The idea is to intentionally push your system to the edge of sustained oscillation, measure two values from that behavior, and then calculate your gains from formulas.

Start by setting Ki and Kd to zero. Gradually increase Kp until the system output oscillates at a constant amplitude, neither growing nor decaying. The gain value where this happens is called the ultimate gain (Ku). Measure the period of those oscillations in seconds or whatever time unit your system uses. That’s the ultimate period (Tu).

From there, calculate your PID gains:

  • Kp = 0.6 × Ku
  • Ki (integral time) = Tu / 2
  • Kd (derivative time) = Tu / 8

These formulas produce a response with some overshoot, roughly a quarter-decay ratio, which is a reasonable tradeoff between speed and stability. If your application needs less overshoot, reduce Kp below the 0.6 × Ku value. For a PI-only controller (no derivative), use Kp = 0.45 × Ku and set the integral time to Tu / 1.2.

One important caveat: Ziegler-Nichols assumes you can safely push the system to sustained oscillation. If your process involves temperature, pressure, or anything where sustained oscillation could cause damage, use an open-loop step-response method instead or tune very conservatively.

Filter the Derivative Term

The derivative term is the most sensitive to noise. It calculates the rate of change of the error signal, so even small, rapid fluctuations from sensor noise get amplified into large output spikes. This creates high-frequency oscillation that has nothing to do with your actual process.

The standard fix is adding a low-pass filter to the derivative term. Most PID implementations include a derivative filter parameter, often labeled N. This filter lets slow changes through (the real process dynamics you want to react to) while blocking the fast noise. A lower N value filters more aggressively, which reduces noise amplification but also slows down the derivative response. A higher N gives you a faster-reacting derivative but amplifies more noise. Typical values for N range from 5 to 20, but the right setting depends on how noisy your sensor is.

If you’re implementing a PID controller in software and your derivative term doesn’t have a built-in filter, you can add a simple first-order low-pass filter in series with the controller output or apply it directly to the derivative calculation. Even a basic exponential moving average on the error signal before the derivative computation can make a dramatic difference.

Add a Dead Band Near the Setpoint

Some systems oscillate only when they’re very close to the setpoint. The error is tiny, but the controller keeps making small corrections back and forth, especially in systems with high sensitivity or low inertia. This creates micro-oscillations that never fully settle.

A dead band solves this by defining a small range around the setpoint where the controller output is forced to zero. If the measured value is within, say, ±2 units of the setpoint, the controller stops correcting entirely. Research on DC motor positioning systems found that introducing a dead band threshold of ±2 units completely eliminated residual oscillations. The output signal flattened once the motor entered the tolerance zone, and the system held its position without further hunting.

The tradeoff is precision. A dead band means you’re accepting a small steady-state error equal to the width of the band. For applications like room temperature control or basic position holding, that’s perfectly fine. For applications requiring zero-error precision, you’ll need to keep the dead band very tight or rely on other methods.

Check Your Loop Timing

In software-based PID controllers, the rate at which your control loop runs directly affects stability. If the loop runs too slowly relative to how fast your process changes, the controller is always reacting to outdated information, which creates oscillation. If the loop timing is inconsistent (sometimes 10 milliseconds, sometimes 50), the integral and derivative calculations become unreliable because they depend on knowing the time interval between updates.

A common rule of thumb is that your control loop should run at least 5 to 10 times faster than the fastest dynamics you need to control. If your system has a natural response time of 100 milliseconds, your loop should update every 10 to 20 milliseconds at most. Use a hardware timer or interrupt rather than relying on “as fast as possible” loops, because consistent timing matters as much as fast timing.

If you suspect timing is the issue, log your actual loop intervals and check for variability. Even small jitter can cause instability in a tightly tuned controller.

Reduce Integral Windup

Integral windup is a specific problem where the integral term accumulates a large value during a period when the system can’t respond, such as when the actuator is at its physical limit. Once the system does start responding, the bloated integral term causes a massive overshoot followed by oscillation as it slowly unwinds.

The fix is to clamp the integral term so it can’t accumulate beyond a set limit. This is called anti-windup. In practice, you set upper and lower bounds on the integral sum and stop adding to it once those bounds are reached. Many PID libraries include this feature, but if you’re writing your own, it’s just a few lines of code that check the integral accumulator against a maximum value after each update cycle. You should also reset or freeze the integral term when the output is saturated, meaning it’s at the maximum or minimum your actuator can produce.