New Automation: PID Controller

+1

You(We) won’t want to scatter rules/automation across GUI and text.

New Release:

  • Apply limits only to I-part
  • Make Ki dependent from the loop time

I updated the link to the JAR above.

As the limit configuration parameters were changed, you need to remove the PID Rule and add a new one.

I’m not aware how to configure automation modules in text rules.

I faced the same challenge when playing with my heating. So I have been implemented a PWM automation module. I could imagine that many heatings only support on/off and it’s worth to release it when I cleaned up the code a bit.

1 Like

I don’t think it’s possible to write a rule as DSL rule. It would require some additional coding I think.

It’s possible to create a rule with jsr223. Here is an example in JavaScript. It’s without any additional libraries. With some additional libraries it can be written more condense:

I put in some random numbers.

'use strict';

scriptExtension.importPreset("RuleSupport");
scriptExtension.importPreset("RuleSimple");

var sRule = new SimpleRule() {
    execute: function(module, input) {
      print("input:" + input); // input contains all the output values
    }
};

sRule.setName("My PID Rule");
sRule.setTriggers([
    TriggerBuilder.create()
        .withId("my_pid_trigger")
        .withLabel("My PID Trigger")
        .withTypeUID("pidcontroller.trigger")
        .withConfiguration(
            new Configuration({
                "input": "input_item",   // input item name
                "setpoint": "setpoint_item", // setpoint item name
                "integralLowerLimit": 0.0,
                "integralUpperLimit": 10.0,
                "loopTime": 1000,
                "kp": 0.4,
                "ki": 1.0,
                "kd": 1.0,
                "kdTimeConstant": 1.0
            })).build()
    ]);
automationManager.addRule(sRule);

There is also an Action pidcontroller.action that can be used to put the output in items. But it looks like this action isn’t implemented correctly. I remember initially not fully understanding how it should work. It only seems to work if your pid trigger has id 1.

Edit: updated renamed integralLowerLimit and integralUpperLimit.

The limit parameters are now integralLowerLimit and integralUpperLimit.

I don’t understand this 1. thing neither. Your code didn’t contain the 1.. It doesn’t work without it with OH3 final.

Ah I see. I remember vaguely this problem with 1 and thought this was in my code :grinning_face_with_smiling_eyes: I did experiment with it, and did research it, but didn’t find the time, back then, to find out how it actually should work. I didn’t see any other actions that take input from triggers. So I don’t know how it’s supposed to work. Maybe just split input on the last dot and use the last part as the name to check.

I think you are deviating from the idea of a PID controller and you are applying some tuning in the core of the PID controller for a particular application.
It is your choice to go this way, and I fully respect it, but I think it will take you to bigger problems in the future.
Some points that might help:

  1. Instead of limiting the Integral part, find a reset solution for the PID (like a condition for reset, or even a manual reset)
  2. If limiting the Integral part is a must, it should be a dynamic limitation (based on the system overall performance). Something like: if the system is capable of 2 points change in a specified time frame, then Integral max limit = x*abs(Limit). Where Limit should be the overall PID limit.

@george.erhan @fwolter My practical problem with the integral part that it is counted on an infinite time window. So any unbalance betweenn positive and negative error will result the integral drift to one direction. Not sure how industrial controllers deal with this.

Would it be anti-pattern to implement a temporal integral where the integration time window (number of loops) is configurable? This would eliminate the infinite accumulation. Someone could still configure a large time window if that is preferred.

So, your problem is tuning.
The industrial controllers permit infinite accumulation, but as I stated before, implement reset methods.
The fact that your integral part was huge, means the PID is not properly tuned.
I think the best approach is to reset the integral based on some conditions (e.g external reset switch, triggered by some other particular rules).

@george.erhan I’m very happy to hear your feedback! Of course I don’t want to deviate from controlling means. That doesn’t help anyone.

Would that result in a sawtooth of the I-part? What would be the reset condition at a real world system/example? Sorry for asking dumb questions. My experience in controlling is still limited :slight_smile:

I was thinking about this; for my application I would be controlling thermostatic radiator valves. After the heating has been shut off overnight I would need some way of resetting the PID controller so that the integral part is reset and the controller can start fresh for the next heating cycle. I would have thought either a Boolean switch or a method to reset the integral part to zero would work.

Let me explain with a real life example:
We assume we have a system that controls ambient temperature, a slow system that does not really require a derivative part. Assuming we have a measured value of 20 degrees Celsius and a set point of 23 degrees Celsius, the output of the PID would first be positive with a proportional part that encapsulates the 3 degrees error and an initial integral of 0. After the 1st loop the integral shall become greater than 0. Now, because we assume we have a system properly designed, the system responds with an increase of the measured value of 21,5, thus the proportional value decreases and the integral increases but with a smaller increment. This means that the PID output increment cools down.
The moment the system responds with a measured value equal to the set point, the proportional value becomes 0 and the integral part does not increase.
Next step the system over runs and the proportional part becomes negative and the integral part decreases. The next loops should calm the PID increment to the point of getting to zero or even negative (this is where the oscillation part starts, that’s why you need limiting for the output of the PID, or set some external decision rules based on the output). This example explains the working model for slow control loop properly tuned with no derivative part involved.
When dealing with PID control, tuning is very important. I know the concept of the PID controller is abstract and if I shall have time and @fwolter would be willing to help, I can develop an auto tuning feature of a PID controller (and it seems is necessary for this automation module).

1 Like

OK, so in my practical example of a TRV heating control system that only works for part of a day, what should happen to the PID controller during the period when control is not required e.g. overnight? If the controller continues to run (loop) it will accumulate a large integral error which might cause an issue when control is resumed. Maybe this is not a problem? However, it would seem to me that I would need to be able to reset the controller when starting the next heating cycle.

If “it works part of the day” does it mean you have a set point? Why don’t you set the set point to a lower temperature and have a PID output of 0 (lower limit set to 0) for that period of time?

No, there would be no set point for part of the day (actually night time). The boiler would be turned off and the TRVs closed. It would seem to me during this period I would need to stop the PID controller from looping or be able to reset it when the system is restarted the next day.

You could disable the PID rule via the REST interface: Design Pattern: Rule Disable That resets the PID.

Yes, maybe I need to approach this from another angle. Possibly setting a low setpoint on all TRVs to effectively shut down the heating. I would need to add some logic to control the boiler so that it is only activated when the radiators require heat e.g. sum of all TRV valve percentages is greater than ‘x’. That might be a more efficient way of running the boiler anyway and stop it cycling on/off when heat is not needed (i.e. when TRVs have closed).

Thanks - that’s useful information.

@george.erhan Could you answer my question on the integral limit vs reset topic? If we take the example of the PV zero export control as mentioned in the first message of this thread, the control loop is regularly failing to reach the setpoint when the battery is empty or the building’s power consumption is too high. I’m wondering how to keep the I part in a reasonable range, then?

When you say “reset” do you mean to reset it to zero or to a specific value?

Resetting should be done for the time dependent parts of the PID, I and D. Resetting means setting the value to 0 (no influence on the PID output).

Here we have 2 possibilities:

  1. The system is not capable of reaching the set point - this should always be treated with a limit on the overall PID (the integral internal value should infinitely accumulate, but the total PID output should be limited). When setpoint is changed a PID reset should occur.
  2. The system is capable of reaching the setpoint, then the properly tuned PID should naturally oscillate using the Integral part.

To conclude: A PID reset should be done when constants are changed, setpoint is changed, and probably an external triggered reset would be of help.

+1. I think this would be more elegant than disabling/enabling the PID Rule.

In the example of the PV zero export, the setpoint is always 0, as the power consumption from the grid should be 0. What could be the reset condition, then?