How to analyze for and make controller adjustments?

I admit I’m a bit lost regarding how to determine if the controller is behaving appropriately for my cooler/heater configuration. I see a lot of other posts with graphs and recommendations on what changes to tweak.

Is there a primer on how to do this analysis for those of us not at all versed in control theory?

This is my first brewpi brew and things look good, but uncertain if I’m able to actually judge these things appropriately.

Only a day into the profile so far.

Any feedback would be appreciated.
Thanks
-Fabrizio.

1 Like

Hi Fabrizio,

I have just answered the same question here:

Read that post and especially the one a few posts further for your issue.

Elco

Will do. Thank you very much.

Hi Elco,

I thought I had everything set up appropriately. (NOT using the beta), but now I’m wondering, and possibly confused more than I was before.

I’d like to figure out how to read the graphs well enough to understand your comments in the other post. Primarily: Why is my heater on for 30-60 minutes every couple of hours. The chill/heat cycle seems a bit excessive. I’m not a math guy.

With a beer-to-fridge Kp of 2, I see the cooler turn on when fridge temp is 2 deg. below beer temp. I admit I don’t understand the “proportional” part of the equation at all and what happens during what I think you call “integrator windup” occurring after Ti if some condition isn’t met. With the beer temp very close to the beer setpoint, certainly close or within error tolerance for the sensor, why the 2-3 degree chill, reheat cycle?
Heating cycle seems to overshoot the fridge setpoint by a couple of degrees and it oscillates with very little/no appreciable change in beer temp.

Does this mean the Td for beer-to-fridge needs to be increased significantly?
In the other post, you observe/calculate that it takes 5-6 hours to effect beer temp. What exactly in the graph data provided you that insight? Please teach (pref. in context of my data so I can play along).

A potential concern:

When I look at my controller state JSON outptut, I see that all of the sensor details are disconnected with null values. The post you referred me to definitely shows connected sensors where mine do not. all of my p,i,d values are also zeros, so something seems off…

How are people posting their controller state JSON all pretty-printed?

Here’s what I see, just cut-n-pasted…

{
  "kind": "Control",
  "pids": [
    {
      "kind": "Pid",
      "name": "heater1",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "fridge",
        "sensor": {
          "kind": "TempSensorDisconnected",
          "value": null,
          "connected": false
        }
      },
      "inputError": 0,
      "Kp": 10,
      "Ti": 600,
      "Td": 60,
      "p": 0,
      "i": 0,
      "d": 0,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 0,
        "period": 4,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 1800000,
            "lastActiveTime": 4293167296
          },
          "target": {
            "kind": "ActuatorNop",
            "state": false
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "heater2",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "beer2",
        "sensor": {
          "kind": "TempSensorDisconnected",
          "value": null,
          "connected": false
        }
      },
      "inputError": 0,
      "Kp": 10,
      "Ti": 600,
      "Td": 60,
      "p": 0,
      "i": 0,
      "d": 0,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 0,
        "period": 4,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 1800000,
            "lastActiveTime": 4293167296
          },
          "target": {
            "kind": "ActuatorNop",
            "state": false
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "cooler",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "fridge",
        "sensor": {
          "kind": "TempSensorDisconnected",
          "value": null,
          "connected": false
        }
      },
      "inputError": 0,
      "Kp": 10,
      "Ti": 1800,
      "Td": 200,
      "p": 0,
      "i": 0,
      "d": 0,
      "actuatorIsNegative": true,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 0,
        "period": 1200,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 1800000,
            "lastActiveTime": 4293167296
          },
          "target": {
            "kind": "ActuatorTimeLimited",
            "minOnTime": 120,
            "minOffTime": 180,
            "maxOnTime": 65535,
            "active": false,
            "target": {
              "kind": "ActuatorNop",
              "state": false
            }
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "beer2fridge",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "beer1",
        "sensor": {
          "kind": "TempSensorDisconnected",
          "value": null,
          "connected": false
        }
      },
      "inputError": 0,
      "Kp": 2,
      "Ti": 7200,
      "Td": 1200,
      "p": 0,
      "i": 0,
      "d": 0,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorSetPoint",
        "targetSetPoint": {
          "kind": "SetPointSimple",
          "value": null
        },
        "targetSensor": {
          "kind": "TempSensor",
          "name": "fridge",
          "sensor": {
            "kind": "TempSensorDisconnected",
            "value": null,
            "connected": false
          }
        },
        "referenceSetPoint": {
          "kind": "SetPointSimple",
          "value": null
        },
        "output": 0,
        "achieved": -0.0039,
        "minimum": -10,
        "maximum": 10
      }
    }
  ],
  "sensors": [
    {
      "kind": "TempSensor",
      "name": "fridge",
      "sensor": {
        "kind": "TempSensorDisconnected",
        "value": null,
        "connected": false
      }
    },
    {
      "kind": "TempSensor",
      "name": "beer1",
      "sensor": {
        "kind": "TempSensorDisconnected",
        "value": null,
        "connected": false
      }
    },
    {
      "kind": "TempSensor",
      "name": "beer2",
      "sensor": {
        "kind": "TempSensorDisconnected",
        "value": null,
        "connected": false
      }
    }
  ],
  "actuators": [
    {
      "kind": "ActuatorPwm",
      "value": 0,
      "period": 1200,
      "minVal": 0,
      "maxVal": 100,
      "target": {
        "kind": "ActuatorMutexDriver",
        "mutexGroup": {
          "kind": "ActuatorMutexGroup",
          "deadTime": 1800000,
          "lastActiveTime": 4293167296
        },
        "target": {
          "kind": "ActuatorTimeLimited",
          "minOnTime": 120,
          "minOffTime": 180,
          "maxOnTime": 65535,
          "active": false,
          "target": {
            "kind": "ActuatorNop",
            "state": false
          }
        }
      }
    },
    {
      "kind": "ActuatorPwm",
      "value": 0,
      "period": 4,
      "minVal": 0,
      "maxVal": 100,
      "target": {
        "kind": "ActuatorMutexDriver",
        "mutexGroup": {
          "kind": "ActuatorMutexGroup",
          "deadTime": 1800000,
          "lastActiveTime": 4293167296
        },
        "target": {
          "kind": "ActuatorNop",
          "state": false
        }
      }
    },
    {
      "kind": "ActuatorPwm",
      "value": 0,
      "period": 4,
      "minVal": 0,
      "maxVal": 100,
      "target": {
        "kind": "ActuatorMutexDriver",
        "mutexGroup": {
          "kind": "ActuatorMutexGroup",
          "deadTime": 1800000,
          "lastActiveTime": 4293167296
        },
        "target": {
          "kind": "ActuatorNop",
          "state": false
        }
      }
    }
  ],
  "setpoints": [
    {
      "kind": "SetPointNamed",
      "name": "beer1set",
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      }
    },
    {
      "kind": "SetPointNamed",
      "name": "beer2set",
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      }
    },
    {
      "kind": "SetPointNamed",
      "name": "fridgeset",
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      }
    }
  ]
}

There are a lot of debug messages about the controller receiving new settings twice a second…

Apr 26 2016 13:31:00 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:00 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:01 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:01 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:02 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:02 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:03 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:03 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:04 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:04 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:05 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:06 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.53
Apr 26 2016 13:31:06 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.52
Apr 26 2016 13:59:54 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.51
Apr 26 2016 14:28:41 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.5
Apr 26 2016 14:57:30 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.49
Apr 26 2016 15:26:17 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.48
Apr 26 2016 15:55:05 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.47
Apr 26 2016 16:23:54 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.46
Apr 26 2016 16:52:41 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.45
Apr 26 2016 17:21:29 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.44
Apr 26 2016 17:50:18 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.43
Apr 26 2016 18:19:05 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.42
Apr 26 2016 18:47:55 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.41
Apr 26 2016 19:16:42 controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 64.4

And my installed/available devices:

Apr 26 2016 19:30:58 Installed devices received: [{"a": "28FF7E5E9015012F", "c": 1, "b": 0, "d": 0, "f": 6, "i": 0, "h": 2, "j": 0.0, "p": 0, "t": 1, "v": 64.398}, {"a": "28FF451C90150380", "c": 1, "b": 1, "d": 0, "f": 9, "i": 1, "h": 2, "j": 0.0, "p": 0, "t": 1, "v": 64.398}, {"a": "28FF1F8590150166", "c": 1, "b": 0, "d": 0, "f": 5, "i": 2, "h": 2, "j": 0.0, "p": 0, "t": 1, "v": 62.375}, {"c": 1, "b": 0, "d": 0, "f": 3, "i": 3, "h": 1, "p": 17, "t": 4, "v": 10.0, "x": 0}, {"c": 1, "b": 0, "d": 0, "f": 2, "i": 4, "h": 1, "p": 16, "t": 4, "v": 0.0, "x": 0}]
Apr 26 2016 19:30:59 Available devices received: [{"c": 1, "b": 0, "d": 0, "f": 0, "i": -1, "h": 1, "p": 11, "t": 0, "x": 0}, {"c": 1, "b": 0, "d": 0, "f": 0, "i": -1, "h": 1, "p": 10, "t": 0, "x": 0}]

Thanks for your patience and assistance!!!
-Fabrizio

Try hitting the refresh button a few times for the control algorithm tab. I think your JSON is out of date. It is not possible for the sensors to be null, but have everything working.

The heater and cooler are toggled to keep the fridge temp at the fridge setpoint. Beer temp has nothing to do with this. Beer temp just determines what the fridge setpoint should be. In your case, apparently, it should be 3F under the beer temp.

When you see heating in the chart, this can be 0-100%. When you see cooling in the chart, it is 100% ON. This will be changed in a later version to more accurately reflect what is happening.

It seems that when cooling, you tend to overshoot. Reduce Kp for the heater and set Td to 600 (this seems to be the time it overshoots).
Your heater also seems to overshoot. Set Td to 600 for the heater as well.

You can also increase the dead time to 1 or 2 hours to prevent alternating between heating and cooling.

This is a pretty good article on PID: http://www.csimn.com/CSI_pages/PIDforDummies.ht`ml

Also when posting lots of formatted text, paste it as code. Use 3 backticks before and after the block

```
Code here
```

Will render as

Code here

Thanks Elco. Will give these a try.
Is Dead Time measured in seconds?
How far to “reduce” the Kp on Heater 1? turn it down by half, a third?

Also, now see sensor values in the JSON output, but “connected: false” still seems wacko…

Cooler Td: 200 -> 600
Heater Td: 60 -> 600
Heater Kp: 10 -> 5 ???
Dead Time: 1800 (30 min?) -> 5400 (90 min?)

{
  "kind": "Control",
  "pids": [
    {
      "kind": "Pid",
      "name": "heater1",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "value": 16.3203
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "fridge",
        "sensor": {
          "kind": "OneWireTempSensor",
          "value": 17,
          "connected": false,
          "address": "28FF1F8590150166",
          "calibrationOffset": 0
        }
      },
      "inputError": 0.6797,
      "Kp": 2.7773,
      "Ti": 600,
      "Td": 600,
      "p": -1.8906,
      "i": 0,
      "d": -0.3281,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 0,
        "period": 4,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 5400000,
            "lastActiveTime": 164547516
          },
          "target": {
            "kind": "ActuatorPin",
            "state": false,
            "pin": 16,
            "invert": false
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "heater2",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "beer2",
        "sensor": {
          "kind": "OneWireTempSensor",
          "value": 18,
          "connected": false,
          "address": "28FF7E5E9015012F",
          "calibrationOffset": 0
        }
      },
      "inputError": 0,
      "Kp": 10,
      "Ti": 600,
      "Td": 60,
      "p": 0,
      "i": 0,
      "d": 0,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 0,
        "period": 4,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 5400000,
            "lastActiveTime": 164547516
          },
          "target": {
            "kind": "ActuatorNop",
            "state": false
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "cooler",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "value": 16.3203
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "fridge",
        "sensor": {
          "kind": "OneWireTempSensor",
          "value": 17,
          "connected": false,
          "address": "28FF1F8590150166",
          "calibrationOffset": 0
        }
      },
      "inputError": 0.6797,
      "Kp": 10,
      "Ti": 1800,
      "Td": 200,
      "p": -6.7969,
      "i": -5.0117,
      "d": -0.3906,
      "actuatorIsNegative": true,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 12.1992,
        "period": 1200,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 5400000,
            "lastActiveTime": 164547516
          },
          "target": {
            "kind": "ActuatorTimeLimited",
            "minOnTime": 120,
            "minOffTime": 180,
            "maxOnTime": 65535,
            "active": false,
            "target": {
              "kind": "ActuatorPin",
              "state": false,
              "pin": 17,
              "invert": false
            }
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "beer2fridge",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "value": 17.8086
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "beer1",
        "sensor": {
          "kind": "OneWireTempSensor",
          "value": 17.9375,
          "connected": false,
          "address": "28FF451C90150380",
          "calibrationOffset": 0
        }
      },
      "inputError": 0.1289,
      "Kp": 2,
      "Ti": 7200,
      "Td": 1200,
      "p": -0.2578,
      "i": -1.2305,
      "d": 0,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorSetPoint",
        "targetSetPoint": {
          "kind": "SetPointSimple",
          "value": 16.3203
        },
        "targetSensor": {
          "kind": "TempSensor",
          "name": "fridge",
          "sensor": {
            "kind": "OneWireTempSensor",
            "value": 17,
            "connected": false,
            "address": "28FF1F8590150166",
            "calibrationOffset": 0
          }
        },
        "referenceSetPoint": {
          "kind": "SetPointSimple",
          "value": 17.8086
        },
        "output": -1.4883,
        "achieved": -0.8086,
        "minimum": -10,
        "maximum": 10
      }
    }
  ],
  "sensors": [
    {
      "kind": "TempSensor",
      "name": "fridge",
      "sensor": {
        "kind": "OneWireTempSensor",
        "value": 17,
        "connected": false,
        "address": "28FF1F8590150166",
        "calibrationOffset": 0
      }
    },
    {
      "kind": "TempSensor",
      "name": "beer1",
      "sensor": {
        "kind": "OneWireTempSensor",
        "value": 17.9375,
        "connected": false,
        "address": "28FF451C90150380",
        "calibrationOffset": 0
      }
    },
    {
      "kind": "TempSensor",
      "name": "beer2",
      "sensor": {
        "kind": "OneWireTempSensor",
        "value": 18,
        "connected": false,
        "address": "28FF7E5E9015012F",
        "calibrationOffset": 0
      }
    }
  ],
  "actuators": [
    {
      "kind": "ActuatorPwm",
      "value": 12.1992,
      "period": 1200,
      "minVal": 0,
      "maxVal": 100,
      "target": {
        "kind": "ActuatorMutexDriver",
        "mutexGroup": {
          "kind": "ActuatorMutexGroup",
          "deadTime": 5400000,
          "lastActiveTime": 164547516
        },
        "target": {
          "kind": "ActuatorTimeLimited",
          "minOnTime": 120,
          "minOffTime": 180,
          "maxOnTime": 65535,
          "active": false,
          "target": {
            "kind": "ActuatorPin",
            "state": false,
            "pin": 17,
            "invert": false
          }
        }
      }
    },
    {
      "kind": "ActuatorPwm",
      "value": 0,
      "period": 4,
      "minVal": 0,
      "maxVal": 100,
      "target": {
        "kind": "ActuatorMutexDriver",
        "mutexGroup": {
          "kind": "ActuatorMutexGroup",
          "deadTime": 5400000,
          "lastActiveTime": 164547516
        },
        "target": {
          "kind": "ActuatorPin",
          "state": false,
          "pin": 16,
          "invert": false
        }
      }
    },
    {
      "kind": "ActuatorPwm",
      "value": 0,
      "period": 4,
      "minVal": 0,
      "maxVal": 100,
      "target": {
        "kind": "ActuatorMutexDriver",
        "mutexGroup": {
          "kind": "ActuatorMutexGroup",
          "deadTime": 5400000,
          "lastActiveTime": 164547516
        },
        "target": {
          "kind": "ActuatorNop",
          "state": false
        }
      }
    }
  ],
  "setpoints": [
    {
      "kind": "SetPointNamed",
      "name": "beer1set",
      "setPoint": {
        "kind": "SetPointSimple",
        "value": 17.8086
      }
    },
    {
      "kind": "SetPointNamed",
      "name": "beer2set",
      "setPoint": {
        "kind": "SetPointSimple",
        "value": null
      }
    },
    {
      "kind": "SetPointNamed",
      "name": "fridgeset",
      "setPoint": {
        "kind": "SetPointSimple",
        "value": 16.3203
      }
    }
  ]
}

Indeed strange that it is showing connected as false, I do not see that issue here.
Are you running 0.4.3?

Cooler Td: 200 -> 600
Heater Td: 60 -> 600
Heater Kp: 10 -> 5
Heater Ti: 1800
Cooler Ti: 3600

Why is your cooler Kp set to 2.7? I think it was incorrectly scaled due to a bug in 0.4.2, which I fixed in 0.4.3.
Please upgrade your controller first.

no. 4.2.0 currently.

Can I upgrade while I have a brew running?
anything special i need to do?

Elco,

Everything upgraded on the master branch. controller is on 0.4.3-g4d00879.

I corrected the Heater Kp to 5 along with the re-confirming the earlier changes. will see how things go overnight.

File downloaded successfully
Programming done
 
Updating firmware over DFU finished

 Waiting for device to reset.
 Apr 28 2016 01:11:52   Opening serial port
 Checking new version: Found BrewPi v0.4.3 build 0.4.3-0-g4d00879, running on a Particle Photon with a V2 shield on port /dev/ttyACM0

 Resetting EEPROM to default settings
 INFO MESSAGE 15: EEPROM initialized
 Now checking which settings and devices can be restored...
 Trying to restore compatible settings from 0.4.2 to 0.4.3
 Migrating these settings: [["tempFormat", "F"], ["fridgeSet", null], ["beerSet", 63.78], ["mode", "p"], ["heater1_kp", 2.78], ["heater1_ti", 600], ["heater1_td", 600], ["heater1_infilt", 1], ["heater1_dfilt", 4], ["heater2_kp", 10.0], ["heater2_ti", 600], ["heater2_td", 60], ["heater2_infilt", 1], ["heater2_dfilt", 4], ["cooler_kp", 10.0], ["cooler_ti", 1800], ["cooler_td", 200], ["cooler_infilt", 1], ["cooler_dfilt", 4], ["beer2fridge_kp", 2.0], ["beer2fridge_ti", 7200], ["beer2fridge_td", 1200], ["beer2fridge_infilt", 1], ["beer2fridge_dfilt", 4], ["beer2fridge_pidMax", 18.0], ["minCoolTime", 120], ["minCoolIdleTime", 180], ["heater1PwmPeriod", 4], ["heater2PwmPeriod", 4], ["coolerPwmPeriod", 1200], ["deadTime", 5400]]
 Omitting these settings: []
 INFO MESSAGE 12: Received new setting: tempFormat = F
 INFO MESSAGE 12: Received new setting: fridgeSet = null
 INFO MESSAGE 12: Received new setting: beerSet = 63.78
 INFO MESSAGE 12: Received new setting: mode = p
 INFO MESSAGE 12: Received new setting: heater1_kp = 2.78
 INFO MESSAGE 12: Received new setting: heater1_ti = 600
 INFO MESSAGE 12: Received new setting: heater1_td = 600
 INFO MESSAGE 12: Received new setting: heater1_infilt = 1
 INFO MESSAGE 12: Received new setting: heater1_dfilt = 4
 INFO MESSAGE 12: Received new setting: heater2_kp = 10.0
 INFO MESSAGE 12: Received new setting: heater2_ti = 600
 INFO MESSAGE 12: Received new setting: heater2_td = 60
 INFO MESSAGE 12: Received new setting: heater2_infilt = 1
 INFO MESSAGE 12: Received new setting: heater2_dfilt = 4
 INFO MESSAGE 12: Received new setting: cooler_kp = 10.0
 INFO MESSAGE 12: Received new setting: cooler_ti = 1800
 INFO MESSAGE 12: Received new setting: cooler_td = 200
 INFO MESSAGE 12: Received new setting: cooler_infilt = 1
 INFO MESSAGE 12: Received new setting: cooler_dfilt = 4
 INFO MESSAGE 12: Received new setting: beer2fridge_kp = 2.0
 INFO MESSAGE 12: Received new setting: beer2fridge_ti = 7200
 INFO MESSAGE 12: Received new setting: beer2fridge_td = 1200
 INFO MESSAGE 12: Received new setting: beer2fridge_infilt = 1
 INFO MESSAGE 12: Received new setting: beer2fridge_dfilt = 4
 INFO MESSAGE 12: Received new setting: beer2fridge_pidMax = 18.0
 INFO MESSAGE 12: Received new setting: minCoolTime = 120
 INFO MESSAGE 12: Received new setting: minCoolIdleTime = 180
 INFO MESSAGE 12: Received new setting: heater1PwmPeriod = 4
 INFO MESSAGE 12: Received new setting: heater2PwmPeriod = 4
 INFO MESSAGE 12: Received new setting: coolerPwmPeriod = 1200
 INFO MESSAGE 12: Received new setting: deadTime = 5400

During the restore of my devices during the controller upgrade, I did see a couple of WARNING 4 and INFO MESSAGE 21 lines. Can you tell me what they mean? Everything seems okay with the installed sensors…

 Now trying to restore previously installed devices: [{u'a': u'28FF7E5E9015012F', u'c': 1, u'b': 0, u'd': 0, u'f': 6, u'i': 0, u'h': 2, u'j': 0.0, u'p': 0, u't': 1}, {u'a': u'28FF451C90150380', u'c': 1, u'b': 1, u'd': 0, u'f': 9, u'i': 1, u'h': 2, u'j': 0.0, u'p': 0, u't': 1}, {u'a': u'28FF1F8590150166', u'c': 1, u'b': 0, u'd': 0, u'f': 5, u'i': 2, u'h': 2, u'j': 0.0, u'p': 0, u't': 1}, {u'c': 1, u'b': 0, u'd': 0, u'f': 3, u'i': 3, u'h': 1, u'p': 17, u't': 4, u'x': 0}, {u'c': 1, u'b': 0, u'd': 0, u'f': 2, u'i': 4, u'h': 1, u'p': 16, u't': 4, u'x': 0}]
 Restoring device: {"a": "28FF7E5E9015012F", "c": 1, "b": 0, "d": 0, "f": 6, "i": 0, "h": 2, "j": 0.0, "p": 0, "t": 1}
 Photon reports: device updated to: {"i":0,"t":1,"c":1,"b":0,"f":6,"h":2,"d":0,"p":0,"a":"28FF7E5E9015012F","j":  0.000}

 Restoring device: {"a": "28FF451C90150380", "c": 1, "b": 1, "d": 0, "f": 9, "i": 1, "h": 2, "j": 0.0, "p": 0, "t": 1}
 Photon reports: device updated to: {"i":1,"t":1,"c":1,"b":1,"f":9,"h":2,"d":0,"p":0,"a":"28FF451C90150380","j":  0.000}

 Restoring device: {"a": "28FF1F8590150166", "c": 1, "b": 0, "d": 0, "f": 5, "i": 2, "h": 2, "j": 0.0, "p": 0, "t": 1}
 WARNING 4: Falling back on backup sensor.
 WARNING 4: Falling back on backup sensor.
 Photon reports: device updated to: {"i":2,"t":1,"c":1,"b":0,"f":5,"h":2,"d":0,"p":0,"a":"28FF1F8590150166","j":  0.000}

 Restoring device: {"c": 1, "b": 0, "d": 0, "f": 3, "i": 3, "h": 1, "p": 17, "t": 4, "x": 0}
 INFO MESSAGE 21: Back on main sensor instead of backup sensor.
 INFO MESSAGE 21: Back on main sensor instead of backup sensor.
 Photon reports: device updated to: {"i":3,"t":4,"c":1,"b":0,"f":3,"h":1,"d":0,"p":17,"x":0}

 Restoring device: {"c": 1, "b": 0, "d": 0, "f": 2, "i": 4, "h": 1, "p": 16, "t": 4, "x": 0}
 Photon reports: device updated to: {"i":4,"t":4,"c":1,"b":0,"f":2,"h":1,"d":0,"p":16,"x":0}

 Restoring installed devices done!
 ****    Program script done!    ****
BrewPi script will restart automatically.


*** Done updating BrewPi! ***

You can safely ignore that. Because the beer sensor was installed before the fridge sensor, it was using the fall back mode to run on the beer sensor only until the fridge sensor was installed.

Had a bit of a strange heating event or two based on last night’s changes, but after the firmware update and resetting heater Kp from 2.78 to 5 (Annotation D?) things seem to be straightening back out.

Am I still reading a cooling overshoot correctly? cooler is only on for a minute or two. Can’t get any shorter than that, right?
No heating yet

I see the stderr log getting debug messages twice a second with updated beer temp settings. Is it strictly necessary to log that debugging constantly? Any way to turn that debug logging volume down to perhaps only when the setting is actually changes to be different than the prior value? e.g. a BeerSet value changed … versus a continuous loop debug every 500ms?

Apr 28 2016 10:47:43 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:43 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:44 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:44 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:45 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:46 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:46 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:47 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:47 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:48 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:48 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:49 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:49 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:50 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:50 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58
Apr 28 2016 10:47:51 Controller debug message: INFO MESSAGE 12: Received new setting: beerSet = 63.58

ok, before…
With default controller v0.4.2 settings:

And After… things look a lot more chaotic
With upgraded and controller v0.4.3 tweaked settings:

Cooler Td: 600
Heater Td: 600
Heater Kp: 5
Heater Ti: 600
Cooler Ti: 1800
DeadTime: 5400

So, analysis-wise,

  1. why did this appear to over-shoot while cooling for a couple of minutes (purple box annotation) at approx. 3:15 when the beer temp was right on the money?
  2. Only to have to heat for almost an hour and then sit for over the 90-min dead time as the beer temp reacted and exceeded the beer set point?

Still struggling to understand what was said earlier about all of this PID calculation being about the fridge temp control and error/offset from beer temp stuff. Reading the linked article started to provide a basis for understanding, but it’s definitely not “clicking” in my head yet.

Would I benefit from a more powerful heater? ( a low-power fermwrap knock-off currently)
Cooling seems to react very quickly, almost too much cooling?
Seems like the system is still overreacting.

Thanks for your patience!
-Fabrizio

You say you have a fermwrap like heater, is it around the fermenter and heating the beer or the fridge air?
That would explain the overshooting. The algorithm is trying to raise the fridge temperature, but instead is raising your beer temperature.

You set the beer-to-fridge filtering for the derivative to the maximum, so you don’t get those spikes on a each bit flip.

Yes, my fermwrap is directly attached to the outside of the glass carboy.
Should I move it to the inside of the door instead of around the carboy?

To confirm, when you say max-out the filter, you mean the “Beer-to-Fridge Derivative filter delay time” value?
It’s currently at the default 159 seconds, I should change it to 639 seconds?

I have also been experimenting a bit with some of the other settings:

30-Apr 00:06

Beer-to-Fridge proportional gain (Kp) =1
Cooler proportional gain (Kp) =5
Dead Time = 3600

30-Apr 09:00

Beer-to-Fridge proportional gain (Kp) =3
Cooler proportional gain (Kp) =10
Dead Time = 3600
Cooler PWM period (seconds) =100
1-May 12:00 noon
Beer-to-Fridge Derivative filter delay time = 639 (from 159)

Yes

Yes

Don’t do that if your cooler is a compressor. They have a minimum ON and OFF time to protect the compressor from overheating. It after running the compressor does not get enough time to let the pressure drop again, it can overheat. Google compressor short cycling for more info.
I would not use anything shorter than 20 minutes.

Okay. fermwrap taped to side wall (opposite from fridge temp sensor)
Will let this stabilize for a day and see how things go.

Controller JSON:

{
  "kind": "Control",
  "pids": [
    {
      "kind": "Pid",
      "name": "heater1",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "name": "fridgeset",
        "value": 15.832
      },
      "inputSensor": {
        "kind": "TempSensorFallback",
        "onBackupSensor": false,
        "sensor": {
          "kind": "TempSensor",
          "name": "fridge",
          "sensor": {
            "kind": "OneWireTempSensor",
            "value": 17.875,
            "connected": true,
            "address": "28FF1F8590150166",
            "calibrationOffset": 0
          }
        }
      },
      "inputError": 2.0547,
      "Kp": 5,
      "Ti": 600,
      "Td": 600,
      "p": -10.2734,
      "i": 0,
      "d": 3.8086,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 0,
        "period": 4,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 3600000,
            "waitTime": 1693426
          },
          "target": {
            "kind": "ActuatorPin",
            "state": false,
            "pin": 16,
            "invert": false
          }
        }
      }
    },
...
    {
      "kind": "Pid",
      "name": "cooler",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "name": "fridgeset",
        "value": 15.832
      },
      "inputSensor": {
        "kind": "TempSensorFallback",
        "onBackupSensor": false,
        "sensor": {
          "kind": "TempSensor",
          "name": "fridge",
          "sensor": {
            "kind": "OneWireTempSensor",
            "value": 17.875,
            "connected": true,
            "address": "28FF1F8590150166",
            "calibrationOffset": 0
          }
        }
      },
      "inputError": 2.0547,
      "Kp": 10,
      "Ti": 1800,
      "Td": 200,
      "p": -20.5469,
      "i": 0,
      "d": 2.5391,
      "actuatorIsNegative": true,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 18.0078,
        "period": 1200,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 3600000,
            "waitTime": 1693280
          },
          "target": {
            "kind": "ActuatorTimeLimited",
            "minOnTime": 120,
            "minOffTime": 180,
            "maxOnTime": 65535,
            "state": false,
            "target": {
              "kind": "ActuatorPin",
              "state": false,
              "pin": 17,
              "invert": false
            }
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "beer2fridge",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "name": "beer1set",
        "value": 16.3906
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "beer1",
        "sensor": {
          "kind": "OneWireTempSensor",
          "value": 16.4375,
          "connected": true,
          "address": "28FF451C90150380",
          "calibrationOffset": 0
        }
      },
      "inputError": 0.0469,
      "Kp": 3,
      "Ti": 7200,
      "Td": 1200,
      "p": -0.1406,
      "i": -0.418,
      "d": 0,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorSetPoint",
        "targetSetPoint": {
          "kind": "SetPointSimple",
          "name": "fridgeset",
          "value": 15.832
        },
        "targetSensor": {
          "kind": "TempSensor",
          "name": "fridge",
          "sensor": {
            "kind": "OneWireTempSensor",
            "value": 17.875,
            "connected": true,
            "address": "28FF1F8590150166",
            "calibrationOffset": 0
          }
        },
        "referenceSetPoint": {
          "kind": "SetPointSimple",
          "name": "beer1set",
          "value": 16.3906
        },
        "output": -0.5586,
        "achieved": 1.4844,
        "minimum": -18,
        "maximum": 18
      }
    }
  ]
}

Elco,

Here’s how the remainder of the primary ferment looked with the latest changes:

I took you advise, and other’s, to do a DA rest now, so I altered the profile for a 68 deg. rest for a couple of days. The heater turned on after the dead-time delay and exceeded the beer set point in about 4.5 hours, however the heater remained on for another 6 hours after that.

Once again, I’m confused as to what combination of settings would cause this.

Current Control Alg.:

{
  "kind": "Control",
  "pids": [
    {
      "kind": "Pid",
      "name": "heater1",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "name": "fridgeset",
        "value": 22.8672
      },
      "inputSensor": {
        "kind": "TempSensorFallback",
        "onBackupSensor": false,
        "sensor": {
          "kind": "TempSensor",
          "name": "fridge",
          "sensor": {
            "kind": "OneWireTempSensor",
            "value": 22.25,
            "connected": true,
            "address": "28FF1F8590150166",
            "calibrationOffset": 0
          }
        }
      },
      "inputError": -0.6172,
      "Kp": 5,
      "Ti": 600,
      "Td": 600,
      "p": 3.0859,
      "i": 10.543,
      "d": 0.5664,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 14.1953,
        "period": 4,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 1800000,
            "waitTime": 1797515
          },
          "target": {
            "kind": "ActuatorPin",
            "state": false,
            "pin": 16,
            "invert": false
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "heater2",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "name": "beer2set",
        "value": null
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "beer2",
        "sensor": {
          "kind": "OneWireTempSensor",
          "value": 17.9375,
          "connected": true,
          "address": "28FF7E5E9015012F",
          "calibrationOffset": 0
        }
      },
      "inputError": null,
      "Kp": 10,
      "Ti": 600,
      "Td": 60,
      "p": 0,
      "i": 0,
      "d": 0,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 0,
        "period": 4,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 1800000,
            "waitTime": 1797444
          },
          "target": {
            "kind": "ActuatorNop",
            "state": false
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "cooler",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "name": "fridgeset",
        "value": 22.8672
      },
      "inputSensor": {
        "kind": "TempSensorFallback",
        "onBackupSensor": false,
        "sensor": {
          "kind": "TempSensor",
          "name": "fridge",
          "sensor": {
            "kind": "OneWireTempSensor",
            "value": 22.25,
            "connected": true,
            "address": "28FF1F8590150166",
            "calibrationOffset": 0
          }
        }
      },
      "inputError": -0.6172,
      "Kp": 10,
      "Ti": 1800,
      "Td": 200,
      "p": 6.1719,
      "i": -5.1289,
      "d": 0.3906,
      "actuatorIsNegative": true,
      "outputActuator": {
        "kind": "ActuatorPwm",
        "value": 0,
        "period": 1200,
        "minVal": 0,
        "maxVal": 100,
        "target": {
          "kind": "ActuatorMutexDriver",
          "mutexGroup": {
            "kind": "ActuatorMutexGroup",
            "deadTime": 1800000,
            "waitTime": 1797368
          },
          "target": {
            "kind": "ActuatorTimeLimited",
            "minOnTime": 120,
            "minOffTime": 180,
            "maxOnTime": 65535,
            "state": false,
            "target": {
              "kind": "ActuatorPin",
              "state": false,
              "pin": 17,
              "invert": false
            }
          }
        }
      }
    },
    {
      "kind": "Pid",
      "name": "beer2fridge",
      "enabled": true,
      "setPoint": {
        "kind": "SetPointSimple",
        "name": "beer1set",
        "value": 20
      },
      "inputSensor": {
        "kind": "TempSensor",
        "name": "beer1",
        "sensor": {
          "kind": "OneWireTempSensor",
          "value": 20.75,
          "connected": true,
          "address": "28FF451C90150380",
          "calibrationOffset": 0
        }
      },
      "inputError": 0.75,
      "Kp": 2,
      "Ti": 7200,
      "Td": 1200,
      "p": -1.5,
      "i": 4.3516,
      "d": 0.0156,
      "actuatorIsNegative": false,
      "outputActuator": {
        "kind": "ActuatorSetPoint",
        "targetSetPoint": {
          "kind": "SetPointSimple",
          "name": "fridgeset",
          "value": 22.8672
        },
        "targetSensor": {
          "kind": "TempSensor",
          "name": "fridge",
          "sensor": {
            "kind": "OneWireTempSensor",
            "value": 22.25,
            "connected": true,
            "address": "28FF1F8590150166",
            "calibrationOffset": 0
          }
        },
        "referenceSetPoint": {
          "kind": "SetPointSimple",
          "name": "beer1set",
          "value": 20
        },
        "output": 2.8672,
        "achieved": 2.25,
        "minimum": -18,
        "maximum": 18
      }
    }
  ]
}

Thanks for your continued assistance!

Ok, looks like the fridge temperature is now following setpoint spot on.

The heater is doing that, that is why it is heating. It doesn’t care about the beer temperature.
The fridge setpoint is determined by the beer temperature, so the heater is controlled indirectly.

If the setpoint is above the beer temperature, this is due to the integrator.

   {
      "kind": "Pid",
      "name": "beer2fridge",
     /*--- edited out ---*/
      "inputError": 0.75,
      "Kp": 2,
      "Ti": 7200,
      "Td": 1200,
      "p": -1.5,
      "i": 4.3516,
      "d": 0.0156,
     /*--- edited out ---*/

        "minimum": -18,
        "maximum": 18
    }      

The integrator is probably increasing too quickly, so you can increase Ti, for example to 4 or 6 hours instead of 2.
Also increase Td so it ‘looks further into the future’ based on the derivative. I think a good setting would be 3600.

The limit for beer to fridge difference is 18F. If it hits the limit, the integrator is disabled. I would increase Kp, but keep the limit at 18F.

So my recommendation:
Kp = 4, Ti = 14400, Td = 3600.

But you probably will not do temperature steps like this very often, and use longer ramps instead.

Interesting.
I’ll update the settings tonight when I get home.
As well as try to digest the details/logic.

With regards to the temp ramp, you mean to say that if I want to cold crash as quickly as possible, I need to manually account for a more gentle slope on my profile?
Isn’t that the controller’s job?
The controller can’t deal with this severe a change efficiently? (is that the right word in this case?)
Please explain. I’ll also search the forum on this tonight too. Can’t be the first one…

No for cold crashing you would do a big jump like this. But for other cases, not so much. You would give the yeast time to adjust. And yes, it is the task of the controller to do a step response as well as possible :slight_smile: