Multi-point PID calibration

I built a custom hotend with a powerful heater cartridge and a small thermal mass in the heater block. This combination created significant temperature oscillations during printing:

Standard PID tuning at 280°C: When printing at 250°C, temperature fluctuations exceeded ±10°C

I tried to implement an adaptive PID that:

  1. Calibrates PID parameters at multiple temperature points (e.g., 210°C, 220°C, 230°C… 280°C)

  2. Stores a lookup table of temperature → (Kp, Ki, Kd) mappings

  3. Dynamically selects PID parameters based on the current target temperature during operation

After calibrating 8 temperature points (210-280°C with 10°C steps) temperature fluctuations reduced from ±10°C to <±3°C across the entire temperature range

The adaptive PID controller uses a “nearest neighbor” approach:

  • Stores calibrated PID values: pid_table_0: 210.0:29.389:9.796:22.042

  • At runtime, selects parameters from the closest calibrated temperature

Configuration example:

[extruder]
control: pid
pid_table_0: 210.0:29.389:9.796:22.042
pid_table_1: 220.0:30.123:10.012:22.456
pid_table_2: 230.0:31.456:10.234:23.012
# ... more calibration points

Calibration command:

PID_CALIBRATE HEATER=extruder TARGETS=210,220,230,240,250,260,270,280

Implementation: link

Would this be useful?

5 Likes

Yes. I’ve been looking for something like that to work with multiple materials.

Right now, I use different printers for different materials.

Interesting, it seems that you can simply interpolate the datapoints to some degree

While useful can’t this be accomplished using macros without changes to klipper code?

I use a macro package (Klipper Printer Additions 3.0b9.1 - More Than Boring Start-G-Code by Christian Vick | Download free STL model | Printables.com) that accomplishes a similar function with bed mesh VS temperature. It seems it wouldn’t be hard to generate a macro to generate PID values for a range if temperatures and then insert the correct values from the start print macro.

Even what you described requires changing the original code too… And don’t you think that tuning the PID in the slicer, rather than in the firmware, is illogical?

Something like that?

def _interpolate_pid(self, target_temp):
    for i in range(len(self.pid_table) - 1):
        t1, kp1, ki1, kd1 = self.pid_table[i]
        t2, kp2, ki2, kd2 = self.pid_table[i + 1]
        
        if t1 <= target_temp <= t2:
            ratio = (target_temp - t1) / (t2 - t1)
            return (
                kp1 + (kp2 - kp1) * ratio,
                ki1 + (ki2 - ki1) * ratio,
                kd1 + (kd2 - kd1) * ratio
            )

    if target_temp < self.pid_table[0][0]:
        return self.pid_table[0][1:]
    return self.pid_table[-1][1:]

Is it a good idea to use interpolation in the case of PID?

2 Likes

It looks like interpolation.

IDK about good or bad here, but based on points what you showed as example config:

the interpolation error seems to be too small to worry about.

Also, you can always add points and so increase resolution and decrease the error.

(And more sophisticated fit methods would be just an overkill)

Thanks.

1 Like

A linear interpolation is - however within the limits of accuracy (ambient temperature, material, print speed, etc) - an approximation.
But I think it is accurate enough.

1 Like

I’m hoping it’s not just interpolation but actually running multiple PID tuning steps.

I realize that makes the PID turning operation much longer to run but, if it means accurate PID values for different temperatures, then I think it’s worth it.

2 Likes

You’re right - linear interpolation is an approximation, and factors like ambient temperature, airflow, and print speed do affect the optimal PID values. However, for my use case (custom hotend with high power/low thermal mass), even the approximation through linear interpolation showed significant improvement over single-point tuning. The main benefit is that the controller adapts to the drastically different thermal dynamics at 210°C vs 280°C, rather than using parameters optimized for only one temperature.

2 Likes

Yes, it runs full PID autotuning at each temperature point

2 Likes

My 2 cents about implementation.

It seems to me, that adding another pid complicate the code more than it is required. You would have better chances (I think so) if it is incorporated within current one.

The only difference is the allowance to set several value triplets. So simple backward compatible assumption that current triplet is (for example) always at zero temp (or simply min/max), could be enough.

Same for the calibration, if there is only one pid and so the calibration code, you can simply modify it to append/replace 1 value at a time if it is required.

Hope that can slim the actual implementation.

I considered merging into existing ControlPID but chose a separate class to avoid modifying original logic for now.