accion-derivativa-pid-completo

The Derivative Action and the Complete PID

  • 5 min

The derivative action of a PID is the part of the controller that responds to the rate of change of the error to dampen the system’s movement.

In the previous article we saw that the P pushes based on the current error and that the I accumulates past errors. Now we are missing the third piece, the D, which looks at the slope and says: “watch out, this is coming too fast”.

It corrects neither the present nor the past. The derivative tries to foresee the future. To put it with less poetry and more mathematics: it calculates whether the error is increasing or decreasing, and at what speed.

The Intuition behind the D

Think about driving a car and stopping at a traffic light. If you only looked at the distance to the traffic light, you would brake harder the closer you got. That would be a proportional action.

Normally you don’t drive like that (or so I hope). You also look at the speed. If you are going fast, you start braking earlier. If you are going slowly, you can wait longer.

The derivative does something similar. If the system is approaching the target very quickly, the D applies an opposing action to brake before overshooting.

In second-order systems, this is interpreted as artificial damping. It is like adding a software damper.

The Derivative Equation

Mathematically, the derivative action is written like this:

Kd is the derivative gain. The larger it is, the more weight we give to the rate of change of the error.

In a microcontroller, since we don’t have a continuous derivative, we use a finite difference:

And in code:

float derivative = (error - error_previous) / dt;
float D = Kd * derivative;

error_previous = error;
Copied!

Conceptually it is very simple. We subtract the current error minus the previous error and divide by the elapsed time. That gives us the slope.

What the D Achieves

The derivative action usually reduces overshoot and oscillations. That is, it helps the system reach the target without overshooting as much.

It can also improve the settling time because it dampens rebounds. If the P makes the system fast but nervous, the D tries to add a bit of composure.

A well-tuned D makes the system feel more “heavy” and controlled. A poorly tuned D turns sensor noise into command surges. This latter scenario happens very often.

The Noise Problem

The derivative has a major weakness: it amplifies fast signals.

And sensor noise is usually precisely that: small, rapid variations. An ADC fluctuating by a couple of counts, an encoder with quantization, an accelerometer picking up vibrations… all of this might seem minor in the original signal, but when you derive it, it turns into huge spikes.

That’s why in real systems a “pure” derivative is almost never used. The measurement is usually filtered, the derivative itself is filtered, or the derivative is applied to the measured variable instead of the error.

Derivative on the Measurement

There is another important practical detail. If we calculate the derivative of the error, and we suddenly change the setpoint, the error takes an abrupt jump. The derivative of that jump is enormous, and the controller generates an output spike that does not correspond to an actual movement of the plant.

This is called derivative kick.

A common solution is to calculate the derivative on the measurement (PV) instead of on the error:

float derivative_measurement = (measurement - measurement_previous) / dt;
float D = -Kd * derivative_measurement;
Copied!

The negative sign appears because if the measurement rises quickly towards the target, we want to brake. This prevents a reference change from causing an artificial derivative kick.

The Complete PID

Combining the three actions, the classical form of the continuous PID is:

Each term looks at a different part of the history:

  • P: looks at the present error.
  • I: accumulates past errors.
  • D: estimates the future trend.

That’s why the PID has survived for so many decades. It’s not because it’s perfect, but because it is simple, cheap, and surprisingly effective in a huge number of real-world systems.

Conceptual Implementation

A basic PID in C++ would look like this:

float Kp = 2.0;
float Ki = 0.5;
float Kd = 0.1;

float integral_accumulated = 0.0;
float error_previous = 0.0;

float calculatePID(float setpoint, float measurement, float dt) {
    float error = setpoint - measurement;

    float P = Kp * error;

    integral_accumulated += error * dt;
    float I = Ki * integral_accumulated;

    float derivative = (error - error_previous) / dt;
    float D = Kd * derivative;

    error_previous = error;

    return P + I + D;
}
Copied!

This code helps us understand the structure, but it is not yet a production-ready PID. It is missing important things: output limits, anti-windup, derivative filtering, and a deterministic sampling time.

Do not copy this basic PID as-is for a real machine without adding limits and protection against saturation. It’s fine for learning. For moving hardware with energy, it falls short.

The derivative provides dampening. It looks at the speed at which the error changes and helps to brake before overshooting the target.

With P, I, and D we now have the complete controller. The P gives us reaction, the I eliminates steady-state error, and the D smooths out rebounds.