Implementierung eines PID-Controllers

4817
Greg Buehler

Ich habe einen PID-Regler implementiert, aber da ich kein Experte für Regelungstheorie bin, habe ich irgendwelche Randfälle übersehen?

public class PIDController
{
    public enum PIDMode
    {
        Manual,
        Auto,
    }

    public enum PIDAction
    {
        Indirect,
        Direct,
    }

    public PIDMode Mode { get; set; }
    public PIDAction Action { get; set; }

    public double Proportional { get; set; }
    public double Integral { get; set; }
    public double Derivative { get; set; }

    public double Minimum { get; set; }
    public double Maximum { get; set; }

    public double DeltaMinimum { get; set; }
    public double DeltaMaximum { get; set; }

    private double _ProportionalTerm;
    private double _Integrator;
    private double _Derivator;

    public double Setpoint { get; set; }

    private double _Feedback;
    public double Feedback
    {
        get
        {
            return _Feedback;
        }
    }

    public void Calculate(double Input, long Time)
    {
        double output;

        // Compute the error value
        double Error = Setpoint - Input;

        if (Mode == PIDMode.Auto)
        {
            if (Action == PIDAction.Direct)
                Error = 0 - Error;

            // Compute the proportional component
            _ProportionalTerm = 1000.0f * (Error - _Derivator) / (double)Time;

            // Compute the integrator component, clamped to min/max delta movement
            _Integrator += (float)Error * (float)Time / 1000.0f;
            if (_Integrator < DeltaMinimum)
                _Integrator = DeltaMinimum;
            if (_Integrator > DeltaMaximum)
                _Integrator = DeltaMaximum;

            // Add the proportional component
            output = (Proportional * Error);

            // Add the integral component
            output += Integral * _Integrator;

            // Add the derivative component
            output += Derivative * _ProportionalTerm;

            // Clamp output to min/max
            if (output < Minimum)
                output = Minimum;
            if (output > Maximum)
                output = Maximum;
        }
        else
        {
            output = Input;
        }

        // Store values
        _Derivator = Error;

        // Returns the result
        _Feedback = output;
    }
}
Antworten
12

2 Antworten auf die Frage

9
Flexo

Es sieht vernünftig aus, aber ich verstehe nicht, warum Sie den Begriff "Proportional" zu einem Mitglied der Klasse machen müssen. Er muss nicht gespeichert werden. Im besten Fall ist es sinnvoll, ihn mit einem Get abfragen zu können, aber ein Satz scheint irreführend zu sein.

Ich würde nur ungern die öffentliche Einstellung von Integral und Derivatives zulassen. Das Abfragen könnte nützlich sein, aber wenn Sie die Benutzer der Klasse festlegen lassen, erscheint das seltsam.

Das Erzwingen der Skalierung um 1000,0 scheint ebenfalls willkürlich und unflexibel zu sein. Dies wäre aus meiner Sicht als einstellbare Konstante zu betrachten.

5
supercat

Ein Zeitparameter für jede Iteration einer PID-Schleife würde bedeuten, dass sie sicher mit einer variablen Frequenz ausgeführt werden kann. Obwohl es Situationen gibt, in denen dies unvermeidlich sein kann und es Möglichkeiten gibt, solche Variationen sicher zu handhaben, würde ich erwarten, dass die meisten Bedingungen, die dazu führen würden, dass sich die Zeit der Abtastschleife ändert, auch beträchtliche "Störungen" im D-Ausdruck hervorrufen und deren Nützlichkeit einschränken.

Ein Ansatz, den ich bisher noch nicht gesehen habe, ist das Ersetzen der PID-Schleife durch einen IIR-Filter. Eine PID-Schleife ist ein Spezialfall eines IIR-Filters, wobei jedoch die Zeitkonstante des zweiten Abgriffs unendlich ist und die Zeitkonstante des dritten Abgriffs nahezu unendlich ist. Die Differenz zwischen den ersten beiden Abgriffen steht für das Delta und der dritte Abgriff für das Integral. Die Verwendung von "realistischeren" Zeitkonstanten für die Filterabgriffe führt zu Ergebnissen, die sich von einem "reinen" IIR-Filter unterscheiden, jedoch auf eine Weise, die vorteilhaft sein kann. Die Verwendung einer kurzen, aber nicht infinitesimalen Zeitkonstante in der zweiten Stufe ermöglicht es, die Menge hochfrequenten Rauschens zu reduzieren. Die Verwendung einer endlichen Zeitkonstante für den dritten Term ermöglicht die effektive Begrenzung des "Aufwickelns".

Es würde mich interessieren, wenn Sie weitere Diskussionen über das Ausdrücken einer PID als IIR erfahren. detly vor 6 Jahren 0
@detly: Ich glaube nicht, dass ich solche Diskussionen gesehen habe, seit ich das oben geschrieben habe. Wenn man die Frequenzantwort der Integral- und Ableitungsausdrücke und derjenigen des beschriebenen FIR-Filters herausfindet, stimmt die PID-Antwort mit dem Grenzfall der FIR überein, wenn sich die Zeitkonstante der zweiten Stufe gegen null und die dritte Stufe gegen unendlich geht. In Anbetracht der Tatsache, dass die Häufigkeit des Interesses im D-Term begrenzt ist und die gewünschte Abwicklungsmenge für den I-Term erwünscht ist, finde ich es neugierig, dass das FIR-Modell nicht mehr verwendet wird. supercat vor 6 Jahren 0