2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.automation.pidcontroller.internal.handler;
15 import org.eclipse.jdt.annotation.NonNullByDefault;
16 import org.openhab.automation.pidcontroller.internal.LowpassFilter;
19 * The {@link PIDController} provides the necessary methods for retrieving part(s) of the PID calculations
20 * and it provides the method for the overall PID calculations. It also resets the PID controller
22 * @author George Erhan - Initial contribution
23 * @author Hilbrand Bouwkamp - Adapted for new rule engine
24 * @author Fabian Wolter - Add T1 to D part, add debugging ability for PID values
28 private final double outputLowerLimit;
29 private final double outputUpperLimit;
31 private double integralResult;
32 private double derivativeResult;
33 private double previousError;
34 private double output;
39 private double derivativeTimeConstantSec;
41 public PIDController(double outputLowerLimit, double outputUpperLimit, double kpAdjuster, double kiAdjuster,
42 double kdAdjuster, double derivativeTimeConstantSec) {
43 this.outputLowerLimit = outputLowerLimit;
44 this.outputUpperLimit = outputUpperLimit;
48 this.derivativeTimeConstantSec = derivativeTimeConstantSec;
51 public PIDOutputDTO calculate(double input, double setpoint, long lastInvocationMs) {
52 final double lastInvocationSec = lastInvocationMs / 1000d;
53 final double error = setpoint - input;
55 // derivative T1 calculation
56 final double timeQuotient = lastInvocationSec / derivativeTimeConstantSec;
57 if (derivativeTimeConstantSec != 0) {
58 derivativeResult = LowpassFilter.calculate(derivativeResult, error - previousError, timeQuotient);
59 previousError = error;
62 // integral calculation
63 integralResult += error * lastInvocationSec;
64 // limit to output limits
66 final double maxIntegral = outputUpperLimit / ki;
67 final double minIntegral = outputLowerLimit / ki;
68 integralResult = Math.min(maxIntegral, Math.max(minIntegral, integralResult));
72 final double proportionalPart = kp * error;
73 final double integralPart = ki * integralResult;
74 final double derivativePart = kd * derivativeResult;
75 output = proportionalPart + integralPart + derivativePart;
78 output = Math.min(outputUpperLimit, Math.max(outputLowerLimit, output));
80 return new PIDOutputDTO(output, proportionalPart, integralPart, derivativePart, error);