mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik [PID] - D-Regler reagiert nicht


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Muzaffer S. (mzo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

ich arbeite gerade an einem Projekt an der Hochschule. Die 
Aufgabenstellung ist einen PID-Temperaturregler für einen 
Lötbarkeitstester zu programmieren mit den Vorgaben (kurzgefasst):

 - Sollwert Lot: 240°
 - Maximale Heiztemperatur der Heizpatrone: 500°

Habe eigentlich schon alles soweit programmiert und getestet (inklusive 
Anti-Windup,PWM-Regelausgangsteuerung...). Ich habe eine 
Temperaturdifferenz von ungefähr +-2°C.

Hier ist mein Code:
// SystemTaskAbfrage, Umwandlung der Zykluszeit und Zuweisung der Zykluszeit in die Variable 'cycle_time'
fbGetCurTaskIdx();
udint_zclock := _TaskInfo[fbGetCurTaskIdx.index].CycleTime/10000;
int_zclock:= UDINT_TO_INT(udint_zclock);
real_zclock:= INT_TO_LREAL(int_zclock)*0.01;
cycle_time := real_zclock;          // = 0.1

// Nach Abfrage aktuelle Temperaturwerte von MAIN übernehmen
Solltemp   := MAIN.setpoint;
Akttemp    := MAIN.actual_value;

// Regeldifferenz berechnen (Solltemperatur - Isttemperatur)
error := (Solltemp - Akttemp);

// P-Regler beschreiben (Regeldifferenz * Verstärkung kP)
P_part := error * GVL_VAR.kP;

// I-Regler beschreiben
IF GVL_VAR.kI > 0  THEN
  I_Part_Zw_Summe := (delta_error_last_cycle * (cycle_time / GVL_VAR.kI));
  
  IF NOT limit_on_low AND (I_Part_Zw_Summe <0) THEN
  I_part :=  I_part + I_Part_Zw_Summe;
  ELSIF NOT limit_on_high AND (I_Part_Zw_Summe >0) THEN
  I_part :=  I_part + I_Part_Zw_Summe;
  END_IF;
  
  IF I_part > Out_max THEN
    I_part  := Out_max;
  ELSIF I_part < Out_min THEN
    I_part   := Out_min;
  END_IF;
    
ELSIF GVL_VAR.kI <= 0.0 THEN
  I_part := 0.0;
END_IF;

// Manuelles Zurücksetzen des Integrators
if I_Reset then
  I_part := 0.0;
END_IF;

// D-Regler beschreiben
diff_anteil := (error - delta_error_last_cycle) / cycle_time;
D_part := diff_anteil * GVL_VAR.kD;

// Regleroutput berechnen (P+I+D)
output_value := P_part + I_part; //+ D_part;

// Merkbits zur Anti-Windup-Maßnahme beim Integrator
limit_on_low     := FALSE;
limit_on_high   := FALSE;

// Reglerausgang zwischen den Werten Min und Max skallieren (wird benötigt für die PWM)
IF output_value > Out_max THEN
  output_value   := Out_max;
  limit_on_high  := TRUE;
ELSIF output_value < Out_min THEN
  output_value   := Out_min;
  limit_on_low   := TRUE;
END_IF;

// Skalierter Reglerausgang
PID_out := output_value;

// Regeldifferenz für nächsten Zyklus beschreiben
delta_error_last_cycle := error;


Mein Problem ist nun: In meiner Regelung bewirkt der D-Anteil garnichts, 
heisst, D ist bei mir immer 0, da sich (error - delta_error_last_cycle) 
nie ändert und immer 0 ist.

Ist mein Regler soweit richtig programmiert? Denn an sich komme ich ja 
auf die gewünschte Solltemperatur mit +-2°C. Was mich aber stört ist, 
dass der D-Regler nichts bewirkt..

Grüße
Muzaffer


PS.: Variablendeklaration habe ich jetzt erst mal nicht mit reingepackt.

: Bearbeitet durch User
Autor: Sven B. (scummos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Variablenname "delta_error_last_cycle" ist ziemlich verwirrend. Du 
meinst ja eigentlich "error_last_cycle". Das "delta" weist darauf hin, 
dass es sich um eine Differenz handelt, was ja nicht so ist.

Ansonsten muss das Problem ja irgendwie in der Zeile
> diff_anteil := (error - delta_error_last_cycle) / cycle_time;
sein. Gib doch mal die Operanden dieser Rechnung aus und das Ergebnis.

Autor: A. Z. (donvido)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Spätestens wenn du die Solltemperatur sprunghaft änderst sollte sich das 
im D-Term bemerkbar machen. Ist delta_error_last_cycle eventuell keine 
statische Variable und bei jedem Funktionsaufruf auf 0 initialisiert? 
Dann würde aber auch dein I-Term nicht funktionieren.

Autor: Muzaffer S. (mzo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die schnellen Antworten erstmal,

Sven B. schrieb:
> Der Variablenname "delta_error_last_cycle" ist ziemlich verwirrend

Da hast du Recht, weis garnicht wie ich da auf "delta" noch gekommen bin 
:D

Sven B. schrieb:
> Ansonsten muss das Problem ja irgendwie in der Zeile
>> diff_anteil := (error - delta_error_last_cycle) / cycle_time;
> sein. Gib doch mal die Operanden dieser Rechnung aus und das Ergebnis.

Hmm, das Problem ist ich bekomme (error - delta_error_last_cycle) hier 
0, daher ist die komplette gleichung 0 und wird mit D-Anteil = 0 
initialisiert.

A. Z. schrieb:
> Spätestens wenn du die Solltemperatur sprunghaft änderst sollte sich das
> im D-Term bemerkbar machen.

Macht es, aber nur kurzfristig, also nur ein Zyklus und dann ist D 
gleich wieder 0

Also ich habe für den Regler Zykluszeit von 0,1s definiert, is das 
möglich das ich diese zu gering gewählt habe, sodass sich der Regler so 
schnell aufruft, dass er keine Regelfehlerdifferenz findet?

Autor: A. Z. (donvido)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muzaffer S. schrieb:
> Also ich habe für den Regler Zykluszeit von 0,1s definiert, is das
> möglich das ich diese zu gering gewählt habe, sodass sich der Regler so
> schnell aufruft, dass er keine Regelfehlerdifferenz findet?

Na klar, wenn die Temperatur sich so langsam ändert, dass zwischen zwei 
Aufrufen keine Änderung feststellbar ist, dann kann es nicht 
funktionieren.
Du könntest entweder die Zykluszeit verlängern oder aber, wie es sich 
für einen realen PID gehört, dem D-Term ein PT1 Filterglied spendieren.
Dann hättest du ein bisschen länger was vom Sollwertsprung.

Autor: Muzaffer S. (mzo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. Z. schrieb:
> oder aber, wie es sich
> für einen realen PID gehört, dem D-Term ein PT1 Filterglied spendieren

Was ist damit genau gemeint?
Bzw. wie genau muss dass dann im Code umgesetzt werden damit der D-Term 
auch richtig funktioniert.

Sry wenn ich so genau bzw "dumm" Frage, aber das hier ist mein erstes 
Projekt in SPS-Programmierung, daher brauch ich ein bisschen Starthilfe 
damit ich das auch richtig verstehe und umsetzen kann.

Autor: A. Z. (donvido)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry vergiss das mit dem Filter.
Dein D-Term scheint schon richtig zu funktionieren.
Auf Sollwertsprünge kann er ja reagieren und die dauern nunmal nur einen 
Zyklus. Die Auflösung deines Temperatursignals ist vermutlich zu gering. 
Deshalb ist delta_error_last_cycle häufig 0 und ab und zu gibts mal 
einen kurzen Puls. Du könntest wie schon gesagt deine Zykluszeit 
verlängern oder den D-Term auch einfach weglassen.

Autor: Muzaffer S. (mzo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. Z. schrieb:
> Deshalb ist delta_error_last_cycle häufig 0 und ab und zu gibts mal
> einen kurzen Puls.

genau so ist das gerade.

Alles klar, danke für die Antwort, ich werde mal versuchen die 
Zykluszeit zu verlängern.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.