📄 pid_controller.java
字号:
package net.sf.dz.controller;import org.freehold.jukebox.logger.LogChannel;/** * Classical PID - Proportional, Integral, Derivative controller. * * @author Copyright © <a href="mailto:vt@freehold.crocodile.org"> Vadim Tkachenko</a> 2001-2002 * @version $Id: PID_Controller.java,v 1.5 2004/06/28 20:35:46 vtt Exp $ */public class PID_Controller extends AbstractProcessController { /** * Log channel to use. */ public static final LogChannel CH_PID = new LogChannel("PID"); /** * Proportional weight. */ private double P; /** * Integral weight. */ private double I; /** * Integral data set. */ private IntegralSet integralSet; /** * Derivative weight. */ private double D; /** * Differential data set. */ private DifferentialSet differentialSet; /** * Saturation limit. * * The controller is considered saturated if the output absolute value * is greater than this. */ private double saturationLimit; /** * Create unconfigured instance. * * This instance can't be used until <code>configure()</code>d. */ public PID_Controller() { } /** * Create the configured instance. * * @param P Proportional weight. * * @param I Integral weight. * * @param Ispan Integral timespan, milliseconds. * * @param D Derivative weight. * * @param Dspan Derivative timespan, milliseconds. * * @param saturationLimit Anti-windup control value. The controller is * considered saturated if the output absolute value is greater than * this. Zero means no anti-windup will be provided. */ public PID_Controller(final double P, final double I, final long Ispan, final double D, final long Dspan, final double saturationLimit) { this.P = P; this.I = I; this.D = D; this.integralSet = new IntegralSet(Ispan); this.differentialSet = new DifferentialSet(Dspan); this.saturationLimit = saturationLimit; check(); } /** * Check if all the parameters are OK. * * @throws IllegalArgumentException if the argument set didn't make * sense. */ private void check() { // This method should be fast because it will be called at the // beginning of compute() to make sure the controller is initialized // NOTE: Remember that integralSet and differentialSet are possibly // unassigned at this point if (saturationLimit < 0) { throw new IllegalArgumentException("Check parameters: saturationLimit=" + saturationLimit); } if ( P == 0 && I == 0 && D == 0) { throw new IllegalArgumentException("All PID components are zeroed: check the configuration"); } } /** * Read the P, I, D and span values from the configuration. * * @exception Throwable if there's a problem with configuration. */ protected final void configure2() throws Throwable { P = getConfiguration().getDouble(getConfigurationRoot() + ".pid.P"); I = getConfiguration().getDouble(getConfigurationRoot() + ".pid.I.weight"); long Ispan = getConfiguration().getLong(getConfigurationRoot() + ".pid.I.time"); D = getConfiguration().getDouble(getConfigurationRoot() + ".pid.D.weight"); long Dspan = getConfiguration().getLong(getConfigurationRoot() + ".pid.D.time"); saturationLimit = getConfiguration().getDouble(getConfigurationRoot() + ".pid.SL"); System.err.println("Configuration root: " + getConfigurationRoot()); System.err.println("P I/Ispan D/Dspan SL: " + P + " " + I + "/" + Ispan + " " + D + "/" + Dspan + " " + saturationLimit); complain(LOG_DEBUG, CH_PID, "P I/Ispan D/Dspan SL: " + P + " " + I + "/" + Ispan + " " + D + "/" + Dspan + " " + saturationLimit); check(); if (I != 0) { integralSet = new IntegralSet(Ispan); } if (D != 0) { differentialSet = new DifferentialSet(Dspan); } } /** * {@inheritDoc} */ protected final double compute() { try { check(); } catch (IllegalArgumentException iaex) { throw new IllegalStateException("Possibly not initialized or improper configuration, cause: " + iaex.getMessage()); } double pv = getProcessVariable(); double error = getError(); double signal = error * P; lastP = signal; if (I != 0) { double integralInput = error; if (saturationLimit != 0) { if ( (getLastKnownSignal() != null) && (Math.abs(getLastKnownSignal().doubleValue()) > saturationLimit)) { // VT: FIXME: This has to be adjusted according to // anti-windup algorithm. Think about making this a // template method or a decorator. error = 0; } } integralSet.record(getLastModified(), error); lastI = integralSet.getIntegral() * I; signal += lastI; } if (D != 0) { differentialSet.record(getLastModified(), error); lastD = differentialSet.getDifferential() * D; signal += lastD; } lastSignal = signal; final Double NaN = new Double(Double.NaN); if (NaN.equals(new Double(signal))) { throw new IllegalStateException("signal is NaN, components: " + getStatus()); } return signal; } /** * Last known value of P. */ private double lastP = 0; /** * Last known value of I. */ private double lastI = 0; /** * Last known value of #. */ private double lastD = 0; /** * Last known signal value. */ private double lastSignal = 0; /** * {@inheritDoc} */ public ProcessControllerStatus getStatus() { return new PID_Status(getError(), lastSignal, lastP, lastI, lastD); } /** * PID controller status. */ public class PID_Status extends ProcessControllerStatus { /** * Proportional value. */ public final double p; /** * Integral value. */ public final double i; /** * Derivative value. */ public final double d; /** * Create an instance. * * @param error Current error value. * * @param signal Current signal value. * * @param p Current P value. * * @param i Current I value. * * @param d Current D value. */ public PID_Status(final double error, final double signal, final double p, final double i, final double d) { super(error, signal); this.p = p; this.i = i; this.d = d; } /** * Get a string representation of a PID controller status. * * @return A string representation of a status put together by a * superclass, followed by slash delimited P, I, D values. */ public final String toString() { return super.toString() + "/" + p + "/" + i + "/" + d; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -