2 * Copyright (c) 2010-2022 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 double integralResult;
29 private double derivativeResult;
30 private double previousError;
31 private double output;
36 private double derivativeTimeConstantSec;
37 private double iMinResult;
38 private double iMaxResult;
40 public PIDController(double kpAdjuster, double kiAdjuster, double kdAdjuster, double derivativeTimeConstantSec,
41 double iMinValue, double iMaxValue) {
45 this.derivativeTimeConstantSec = derivativeTimeConstantSec;
46 this.iMinResult = Double.NaN;
47 this.iMaxResult = Double.NaN;
49 // prepare min/max for the integral result accumulator
50 if (Double.isFinite(kiAdjuster) && Math.abs(kiAdjuster) > 0.0) {
51 if (Double.isFinite(iMinValue)) {
52 this.iMinResult = iMinValue / kiAdjuster;
54 if (Double.isFinite(iMaxValue)) {
55 this.iMaxResult = iMaxValue / kiAdjuster;
60 public PIDOutputDTO calculate(double input, double setpoint, long lastInvocationMs, int loopTimeMs) {
61 final double lastInvocationSec = lastInvocationMs / 1000d;
62 final double error = setpoint - input;
64 // derivative T1 calculation
65 final double timeQuotient = lastInvocationSec / derivativeTimeConstantSec;
66 if (derivativeTimeConstantSec != 0) {
67 derivativeResult = LowpassFilter.calculate(derivativeResult, error - previousError, timeQuotient);
68 previousError = error;
71 // integral calculation
72 integralResult += error * lastInvocationMs / loopTimeMs;
73 if (Double.isFinite(iMinResult)) {
74 integralResult = Math.max(integralResult, iMinResult);
76 if (Double.isFinite(iMaxResult)) {
77 integralResult = Math.min(integralResult, iMaxResult);
81 final double proportionalPart = kp * error;
83 double integralPart = ki * integralResult;
85 final double derivativePart = kd * derivativeResult;
87 output = proportionalPart + integralPart + derivativePart;
89 return new PIDOutputDTO(output, proportionalPart, integralPart, derivativePart, error);
92 public void setIntegralResult(double integralResult) {
93 this.integralResult = integralResult;
96 public void setDerivativeResult(double derivativeResult) {
97 this.derivativeResult = derivativeResult;