m-lundberg / simple-pid

A simple and easy to use PID controller in Python
MIT License
767 stars 209 forks source link

Question about PID output #33

Closed kratsg closed 2 years ago

kratsg commented 3 years ago

I have a simple use case where I've got a power supply controlling a peltier. The input + setpoint is the temperature I want, and the output of the PID should correspond directly (or proportionally) to the voltage I want to set.

At the moment, I ended up with something like

from simple_pid import PID
pid = PID(-0.5*0.20, -0.4*0.5/24, -0.066*0.5/24, setpoint=15)
pid.proportional_on_measurement = True
pid.sample_time = 1.0
pid.output_limits = (0, 5)

try:
    while True:
        v = ps_peltier.measureVoltage()
        t = get_temperature()
        control = pid(t)
        print(f"{t:0.4f} °C ({v:0.4f} V) -> {control:0.4f} V")
        ps_peltier.setVoltageLevel(control)
        time.sleep(pid.sample_time)
except KeyboardInterrupt:
    ps_peltier.setVoltageLevel(0.0)

where I just tried the Zeigler-Nichols method, and wanted it to stabilize at 15C. It seems to work, and I restricted the outputs from (0,5). The question is -- what is the normal procedure of scaling or remapping the output? Is it just enough to do this? If I wanted to control something that went from (0, 10) instead, or keeping (0,5) but mapping to (1,6) -- where it's linearly mapped, should I just map it outside of the PID control block, or should the PID block always be feeding the output back into the control at a 1:1 mapping?

m-lundberg commented 2 years ago

If I understand you correctly, you should be able to either change the output limits to (0, 10) or (1, 6), or scale/offset the PID output manually. Keep in mind that the output limits is also used to limit integral windup in this implementation, so it would not be exactly equivalent. Which way is better I can't say, it could depend on the circumstances. I'm just a software developer, not an expert in control theory.