PID Climate - Best environment setup?

I’m using the PID Climate component together with the Dallas component for temperature measures and the Slow PWM component for controlling the output to a Triac via a zero crossing optocoupler. It works kind of fine but the derivative part is causing a high noice in the output.

To slow down the temperature variations I have done the following:

  • Used the moving average filter on the Dallas sensor.
    The sample rate is once every second and the moving average is 120 seconds and I release new values to the PID every 5 second.
    I have set the decimal points to 5 but I don’t think this will affect the PID.
  • In the PID I’m averaging the output every 1 sample and the derivative every 5 sample
  • The PWM window is set to 1 second and I’m in the 50Hz mains network so I would get a 0.5% output accuracy

But I still see to many variations on the output. What would be the best approach? Shall I for a start move the PID averaging on the derivative up streams to the sensor, i.e. increasing the moving window 5 times to 5*120=600 seconds. I tried that but it resulted in the PID acted as an on-off switch :wink:
The thinking was that from an auto tuning perspective it would be the best to have the same latency in auto tuning as in operation.
I’m also thinking about adding forced mode to the sensor, would that be better for the PID controller?

The problem with a noisy output signal is that (except for being ugly) it’s very hard to get 100% effect when needed

What experiences do you have?

P.S. In this setup I’m using the PID to control the temperature of a floor with a heating cable in concrete so it would be quite a slow system

This is how it looks like with 5 seconds intervals:
image

image

And over time the heating looks like this:

Dallas sensor:

dallas:
  - pin: GPIO3
    update_interval: 1s

sensor:
  # Dallas temperature sensor
  - platform: dallas
    address: 0xbd3c01d075eac628
    name: "temperature_sensor"
    id: temperature_sensor
    accuracy_decimals: 5
    filters: 
      - sliding_window_moving_average: 
          window_size: 120
          send_every: 5

PWD:

output:
  - platform: slow_pwm
    pin: GPIO1
    id: my_slow_pwm
    period: 1s
    inverted: True
    restart_cycle_on_state_change: False

PID:

climate:
  - platform: pid
    id: pid_climate
    name: "PID Climate Controller"
    sensor: temperature_sensor
    default_target_temperature: 19°C
    heat_output: my_slow_pwm
    visual: 
      temperature_step: 
        current_temperature: 0.01
        target_temperature: 0.1
    control_parameters:
      kp: 0.87308
      ki: 0.00026
      kd: 737.09644
      derivative_averaging_samples: 1
      output_averaging_samples: 5

I use several voor my pool setup,

The lesson I learned the hard way is to calibrate meany in a bowl of water and adding (hot) water, and noting down the deviations then add them to esphome using filter → calibrate_linear and re-test until they matched close enough to my liking.

Still they are not “great” they might be knockoffs however they do the job for me

it also might be wise to test different type of sensors

Thanks. But it’s not the sensors inaccuracy or linearity that’s is the issue, the issue is that the derivative part is so sensitive (the auto tuning sets this to ~700 for me and this makes the output to vary +/- 20 percentage units or more from one 5-second period to another

I think I finally understood how the PID climate component works.

There’s a good thing to send values as frequently as possible to the PID and I now do this every second.
In the code below I have used “force_update” = True. My thinking is that this will keep the PID going all the time and since the PID will average the temperature for the derivate part, this setting is needed.

To get a smooth temperature input value to the PID it might be good to average the temperature sensor and below I’m doing this in a 60 sample window (since my sample rate is 1 second the windows is also 60 seconds).

dallas:
  - pin: GPIO3
    update_interval: 1s

sensor:
  # Dallas temperature sensor
  - platform: dallas
    address: 0xbd3c01d075eac628
    name: "temperature_sensor"
    id: temperature_sensor
    accuracy_decimals: 5
    filters: 
      - sliding_window_moving_average: 
          window_size: 60
          send_every: 1
    force_update: True

How to determine that the averaging is good enough?
I’m doing this by monitoring the proportional parameters from the PID. In below picture I used a 45 sample averaging window and I could see some 1-second spikes in the proportional part.
I could probably also have done this directly on the dallas sensor “temperature_sensor” but I wanted to see this value from the PID

In the picture above you can see that I also have the raw values of the temperature sensor and I used a template sensor for this according to below:

dallas:
  - pin: GPIO3
    update_interval: 1s

sensor:
  # Dallas temperature sensor
  - platform: dallas
    address: 0xbd3c01d075eac628
    name: "temperature_sensor"
    id: temperature_sensor
    accuracy_decimals: 5
    on_raw_value:
      then:
        - sensor.template.publish:
            id: temperature_sensor_raw
            state: !lambda return x;
    filters: 
      - sliding_window_moving_average: 
          window_size: 45
          send_every: 1
    force_update: True

  - platform: template
    name: "temperature_sensor_raw"
    id: temperature_sensor_raw
    device_class: temperature
    state_class: measurement
    unit_of_measurement: "°C"
    accuracy_decimals: 5

And I monitored this using a history-graph visual:

type: history-graph
entities:
  - entity: sensor.iot_esphome_generic_sonoff_02_temperature_sensor
  - entity: sensor.iot_esphome_generic_sonoff_02_temperature_sensor_raw
  - entity: sensor.iot_esphome_generic_sonoff_02_pid_climate_heat
  - entity: sensor.iot_esphome_generic_sonoff_02_pid_climate_proportional
  - entity: sensor.iot_esphome_generic_sonoff_02_pid_climate_inteegral
  - entity: sensor.iot_esphome_generic_sonoff_02_pid_climate_derivate
hours_to_show: 0.05

When I’m happy with smoothing of my temperature sensor (not seeing the 1 second spikes going in the wrong direction) I could start smoothening the derivate part but I will instead first do a auto tuning of the PID.

When Auto tuning is finished (took 6 hours for me) I will start smoothening/averaging the derivate part in the PID setting “derivative_averaging_samples” below.
But… Remember to grab the Auto Tuning parameters from the log before flashing/rebooting the ESP device, I always copy these values into the YAML code and comment them out so that I can go back to them at any time.

climate:
  - platform: pid
    id: pid_climate
    name: "PID Climate Controller"
    sensor: temperature_sensor
    default_target_temperature: 19°C
    heat_output: my_slow_pwm
    control_parameters:
      kp: 0.9
      ki: 0.00031
      kd: 700
      derivative_averaging_samples: 240
      output_averaging_samples: 1
      starting_integral_term: 0.31

I have also used the “starting_integral_term” to continue with the integral term I last had, this just not having to wait for the integration value to be built up again when flashing/restarting the PID HW.

At a “derivative_averaging_samples” or 240 it looked like below so I increased it to 360 and then it looked ok.

Remember I first had an average of 60 seconds and now I averaging that value 360 times so the value the PID gets to work with is some minutes delayed. This will cause the PID to have some overshoots but I’m fine with that.

If I would like the output to be smoothen even more I guess I could have set the “output_averaging_samples” to 2 or even larger, but I leave this for now.

P.S. This system I tuned above represents a bathroom with a heating cable in 20 cm concerts so it’s a slow system. But the principles above should be fine for any system.

For a total understanding of this PID component I also added these Gauge meters:

square: false
type: grid
cards:
  - type: gauge
    entity: sensor.iot_esphome_generic_sonoff_02_pid_climate_heat
    min: 0
    max: 100
    name: Effect (PWM)
  - square: true
    type: grid
    cards:
      - type: gauge
        max: 100
        entity: sensor.iot_esphome_generic_sonoff_02_pid_climate_proportional
        min: -100
        needle: true
        severity:
          green: 0
          yellow: 0
          red: 0
        name: P
      - type: gauge
        max: 100
        entity: sensor.iot_esphome_generic_sonoff_02_pid_climate_inteegral
        needle: true
        min: -100
        severity:
          green: 0
          yellow: 0
          red: 0
        name: I
      - type: gauge
        max: 100
        entity: sensor.iot_esphome_generic_sonoff_02_pid_climate_derivate
        min: -100
        needle: true
        severity:
          green: 0
          yellow: 0
          red: 0
        name: D
    columns: 3
columns: 1

Very interesting project.
I plan to control the proportional valve with a PWM to 0-10V converter.
Just wondering how to connect the HW output with HA to the converter.
I was thinking of putting it on the ESSP32 board, but it would be easier this way.