Zum Hauptinhalt springen

Steuern und Regeln

Steuern und Regeln mit dem Mathemodul

Bei der umfangreichen Funktionsbibliothek des Mathe-Moduls ist es naheliegend, auch Steuer- und Regelungsfunktionen in dieser Script-Sprache zu implementieren.

Dies ist mit einigen Einschränkungen und unter Berücksichtung folgender Punkte tatsächlich möglich:

Signalverarbeitung, Zeitverhalten

Der Vorgang des Steuerns und Regelns erfordert harte Echtzeit-Berechnungen, d.h. eine feste, möglichst kurze Signallaufzeit vom Erfassen der Messgröße bis zur Ausgabe der Stellgröße an den Prozess. In Steuerungen liegt diese typischerweise bei ca. 1 .. 10 ms. Diese harte Randbedingung kann mit der Architektur des smartCORE nicht eingehalten werden!

Messdaten werden von bestimmten PlugIns erfasst und in die Kanäle des smartCORE geschrieben. Dazu asynchron wird in annähernd konstanten, großen Zeitintervallen der Formelsatz des Mathe-Moduls auf die zur Verfügung stehenden Daten gerechnet, sofern für einen Zeitpunkt alle benötigten Kanäle auch Daten bereitstellen. Die Ergebnisse werden im Takt dieser Berechnung in smartCORE Kanäle geschrieben. Dazu asynchron werden Daten aus den smartCORE Kanälen z.B. über CAN an den Prozess ausgegeben.

Es gibt also genügend Stellen, wo die Echtzeit-Forderung durch die Asynchronität im smartCORE, die Kanäle als Puffer oder Ringspeicher und die Batch-Verarbeitung des Mathe-Moduls verletzt wird.

Sind die zu beeinflussenden Prozesse langsam1 genug, kann man zumindest den Berechnungsvorgang und die Ausgabe so anpassen, dass die diskrete Abtastzeit discreteSampleTimeMs mit der Ausführungszeit des Batch-Prozesses evaluationTimeMs und der Ausgabe an den Prozess übereinstimmen. Mögliche Werte sind hier im Bereich 50 .. 1000 ms. Dann werden die Asynchronität und die Pufferung der Datenströme tolerierbar.

Zeitrichtige Berechnung

So zwingend eine zeitrichtige Berechnung von Messdaten für die spätere Analyse und ein Prozess-Monitoring ist, so hinderlich ist sie für Steuer- und Regelvorgänge. Als Grundregel gilt im Mathe-Modul, dass nicht in die Zukunft extrapoliert werden darf. Demnach ist ein Verlauf von Messwerten nur exakt bis zu dem Zeitpunkt gültig und nutzbar, zu dem er zuletzt aktualisiert wurde.

Angenommen, bestimmte Sollwerte oder Schaltbefehle werden als Shared-Attribut aus einem Dashboard geliefert, dann kann es durchaus 2-5 Sekunden dauern, bevor ein neuer Wert zur Verfügung steht.

Angenommen, Wetterdaten, die für die Parametrierung des Regelungsvorgangs benötigt werden, werden von der Wetterstation nur einmal pro Minute geliefert.

In beiden Fällen würde die Steuerung oder Regelung verharren, bis neue Werte vorliegen. Dies ist jedoch unerwünscht. Mittels des Macros #timeless können entsprechende Kanäle aus der zeitrichtigen Berechnung herausgelöst werden. Dann ist der letzte Wert in dem Kanal auch in die Zukunft so lange gültig, bis ein neuer Wert hinzugefügt wird. Dieses Verhalten wird damit erkauft, dass (kurzzeitige) Wertänderungen, die noch vor dem zuletzt aufgrund der Prognose berechneten Ergebniswert liegen, nicht mehr berücksichtigt werden.

Regler

PID Regler "pidCtrl"

Under Construction Diese Funktion ist in der Umsetzung und noch nicht für den produktiven Betrieb vorgesehen.

Die Funktion pidCtrl() implementiert einen Regler mit konfigurierbarem proportionalen (P), integrierenden (I) und differenzierendem (D) Verhalten.

Eingangsparameter der Funktion sind mindestens die Führungsgröße (Sollwert, setpoint) sp und die zu führende Prozessgröße (Istwert, current value) cur. Ausgabe ist die Stellgröße.

Optional kann die Betriebsart über den Eingang mode gewählt werden:

modeBeschreibung
0, falseNormaler Regelbetrieb (Enable)
1, trueStellgröße halten (Hold)
2Stellgröße folgt dem manuellen Steuereingang u_man (Bypass)

Optional können mit dem Eingangsvektor parVec die Regelparameter [K, Ti, Td] auch dynamisch zugewiesen werden. der Vektor kann 1 .. 3 Parameter werte enthalten. Diese überschreiben die Angaben im Konfigurations-Objekt.

important

Die Berechnung erfolgt grundsätzlich mit der diskreten Abtastzeit discreteSampleTimeMs. Damit die Steuergröße zeitnah an den Prozess übergeben werden kann, muss die Ausführungszeit des Batch-Prozesses evaluationTimeMs auf den gleichen Wert eingestellt werden.

u1 = pidCtrl(sp, cur, {...});
u2 = pidCtrl(sp, cur, mode, {...});
u3 = pidCtrl(sp, cur, mode, u_man, {...});
u4 = pidCtrl(sp, cur, mode, u_man, parVec, {...});
// Verpflichtende Konfiguration für alle Varianten
ux = pidCtrl(..., { K: <dbl>
             , Ti: off|<dbl>
                 , Td: off|<dbl>
                 , reverse: <bool>
                 , commonK: <bool>
                 , dWidth: <uint>
                  , lower: off|<dbl>
                  , upper: off|<dbl>
});

Die Beschreibung der Eigenschaften erfolgt mit Beispielen aus dem Zeitbereich, obwohl die Funktion intern in diskreten Abtastschritten rechnet.

EigenschaftWertBeschreibung
K<dbl>Verstärkung des Reglers
Tioff|<dbl>Aktivierung und Integrationszeit für I-Anteil
I(e)=1Tie(t)dtI(e) = \frac{1}{T_i} \cdot \int e(t) dt
Tdoff|<dbl>Aktivierung und Differentiationszeit für D-Anteil
D(e)=Tdddte(t)D(e)=T_d \cdot \frac{d}{dt} e(t)
reverse<bool>Umkehrung der Stellrichtung
false: e=spcure=sp-cur, (def.)
true: e=curspe=cur - sp
commonK<bool>Interpretation der Verstärkung:
false: u=K(e)+I(e)+D(e)u = K(e) + I(e) + D(e)
true: u=K(1+I(e)+D(e))u=K\cdot(1+I(e)+D(e)), (def.)
dWidth<uint>Anzahl der Abtastintervalle zur gewichteten Mittelung des Differentialwertes (def.: 3)
loweroff|<dbl>Untere Begrenzung der Stellgröße,
der integrale Anteil wird nachgeführt, um eine Stoßfreie Wiederaufnahme zu ermöglichen.
upperoff|<dbl>Obere Begrenzung der Stellgröße,

Reglerstruktur: Die Eigenschaft commonK schaltet die Interpretation des Verstärkungsfaktors K. In der Regelungstechnik wirkt K üblicherweise auf alle drei Pfade P, I und D gleichermaßen (commonK: true, def.!) und übernimmt auch die Umwandlung der physikalischen Dimensionen zwischen Regelabweichung (z.B. in hPa) und Stellgröße (z.B. in %). Damit beeinflusst K nicht das dynamische Verhalten des Reglers, das durch seine Pole und Nullstellen bestimmt wird, sondern nur die Agilität und Stabilität des geschlossenen Regelkreises. Viele Einstellregeln für PID-Regler setzen auf dieser Struktur auf.

Selten findet man die Interpretation, dass K tatsächlich nur den proportionalen Pfad des Reglers beeinflusst (commonK: false). Damit verschiebt sich die Aufgabe der Einheitenumwandlung auch auf die Zeitparameter Ti und Td und die Veränderung von K verändert unmittelbar die Pol- und Nullstellen des Reglers und damit sein dynamisches Verhalten. der Abgleich des Reglers wird damit erheblich erschwert.

Zur Nutzung des D-Anteils: Da die Reglerfunktion an die sehr langsame diskrete Taktung des Mathemoduls gebunden ist, ist die Bewertung des Gradienten der Regelabweichung im D-Anteil auch nur mit Vorsicht einzusetzen. Durch die "On-Change" Philosophie bei der Bereitstellung der Messdaten in einem smartCORE-Kanal, können lange Zeitabschnitte entstehen, in denen sich das Signal nicht ändert. Um dennoch z.B. eine langsame Drift einer Temperatur erkennen zu können, werden die Werte mehrere Abtastschritte mit einer Gewichtungsfunktion zum Wert der Ableitung verrechnet. Die Breite dieses Fensters wird durch die Eigenschaft dWidth angegeben. Dadurch entsteht im D-Pfad des Reglers allerdings auch eine zusätzliche Totzeit (dWidth/2 * discreteSampleTimeMs), die den Regelvorgang negativ beeinflussen kann. dWidth ist also so klein wie möglich aber so groß wie nötig zu wählen. Das hängt vom zu regelnden Prozess ab.

Zeitbezug: Für den Fall, dass die Führungsgröße sp aus einem (shared) Attribut stammt und nur selten aktualisiert wird, sollte dieser Kanal unbedingt mittels des Macros #timeless vom Zeitbezug gelöst werden. Gleiches gilt möglicherweise auch für die Prozessgröße cur.

Zustandsautomat (Finite State Machine)

Zustandsautomat "states"

Under Construction Diese Funktion ist in der Umsetzung und noch nicht für den produktiven Betrieb vorgesehen.

Implementierung einer Finite State Machine (FSM) Mit dieser Funktion states() kann ein Verhalten modelliert werden, das aus Zuständen, Zustandsübergängen und Aktionen besteht.

Eine allgemeine Beschreibung findet sich in dem Artikel Finite-state machine - Wikipedia oder auch hier (DE).

Die Auswertung erfolgt in dieser Implementierung getaktet mit der globalen diskreten Abtastzeit discreteSampleTimeMs. In jedem Takt kann genau eine Transition einen Zustandswechsel herbeiführen.

Dieser endliche Zustandsautomat besitzt endlich viele Zustände (States), die durch einen eindeutigen Bezeichner sx identifiziert werden. Jeder Zustand ist stabil, bis ein Zustandsübergang (Transition) einen Wechsel auslöst. Dadurch kann eine Zustand Information über die Vergangenheit beinhalten, da das System ihn ja auf dessen bisherigem Weg erreicht hat, d. h., er reflektiert in gewissem Umfang die Änderungen der Eingabe seit dem Systemstart bis zum aktuellen Zeitpunkt.

s1, … sN: definieren die Bezeichner der States sx der Statemachine als const <uint/int/str> (!) Der erste State ist der Start-State, sofern nicht über die Eigenschaft init: sx ein anderer bestimmt wird. Ausgabe von states() ist der jeweilige Wert von sx des aktiven Zustands, sofern nicht mit der Eigenschaft outIdx: true die Ausgabe des State-Index als [1, 2, … N] erzwungen wird. Alle sx müssen eineindeutig sein, da sie in den transit() Funktionen für die Angabe des nächsten Zustands verwendet werden.

Ein Zustandsübergang (Transition) ist ein Übergang aus dem aktuellen Zustand in einen neuen (anderen) Zustand. Zu diesem Übergang kommt es, wenn die angegebenen logischen Bedingungen / „Eingaben“ vorliegen, die erfüllt sein müssen, um den Übergang zu ermöglichen. In dieser Implementierung stehen dafür eine boolsche Bedingung sowie ein definierbares Zeitfenster, ein Wiederholungszähler und ein Prioritäts-Wert für die Freigabe zur Verfügung.

trXY: definieren transit()-Objekte, die für den zuvor genannten State ausgewertet werden. Die jeweils erste transit() Funktion, für die die konfigurierten Bedingungen zutreffen, löst den Zustandsübergang aus.

Eine besondere Rolle haben Zustandsübergänge, die vor dem ersten Zustand definiert werden. Sie werden in jedem beliebigen Zustand ausgewertet, bevor die am Zustand selbst definierten Transitionen zur Auswertung kommen. Damit übernehmen sie die Rolle von "from any"-Transitionen, z.B. um Fehlerbedingungen abzufangen, TimeOut oder forcierte Rückstellungen zu realisieren.

Die Parameter der Funktion states() beschreiben somit den Automaten, in dem ein const <uint/int/str> Parameter entweder einen neuen Zustand definiert oder mittels transit() Zustandsübergänge aus diesem Zustand definiert werden.

act = states(tr00, tr01, …
, s1, tr10, tr11, …
, s2, tr20, tr21, …);
// Optionale Konfiguration
actX = states(..., { init: <sx>
, outIdx: <bool>
, ageVar: <str>
, dbgVar: <str>
});
EigenschaftWertBeschreibung
init<var>Start-Zustand für den Automaten, sofern nicht per Def. der erste
outIdx<bool>true: Ausgabe des Index des aktiven Zustands <uint> [1,2,N][1, 2, … N]
false: Ausgabe des für den Zustand definierten Bezeichners <uint/int/str>
ageVar<str>Das „Alter“ des aktiven Zustands in Sekunden kann in der hier bezeichneten Variable veröffentlicht werden.
dbgVar<str>Die Knotennummer der jeweils auslösenden Transition wird in die hier bezeichnete Variable geschrieben. "0", wenn keine Transition ansteht.
storage<str>(in Vorbereitung)

Eine Aktion ist die „Ausgabe“ der FSM, die in einer bestimmten Situation erfolgt. Es gibt vier Typen von Aktionen:

  • Eingangsaktion: Die Aktion wird ausgeführt/ausgegeben beim Eintreten in einen Zustand (egal über welchen Zustandsübergang der Zustand erreicht wurde, falls es mehrere gibt).

  • Ausgangsaktion: Die Aktion wird beim Verlassen eines Zustandes generiert (egal über welchen Zustandsübergang der Zustand verlassen wird).

  • Eingabeaktion: Die Aktion wird abhängig vom aktuellen Zustand und der Eingabe generiert. Einem Zustand können also mehrere Aktionen zugeordnet sein, die abhängig davon ausgeführt werden, über welchen Zustandsübergang er erreicht/verlassen wird.

  • Übergangsaktion: Die Aktion wird während eines Zustandsübergangs ausgeführt

Wenn act = state(…) eine Variable ist, die den aktiven Zustand abbildet, lassen sich die zustandsabhängigen Aktion wie folgt realisieren:

  • Eingangsaktion: posedge(act == K)

  • Ausgangsaktion: negedge(act == K)

  • Eingabeaktion: (act == K)

Mit der in der Transition definierbaren actVar: “TR“ können letztlich auch

  • Übergangsaktionen: TR

reslisiert werden.

Transitionen "transit"

Under Construction Diese Funktion ist in der Umsetzung und noch nicht für den produktiven Betrieb vorgesehen.

Die Funktion transit() erzeugt die Transitions-Objekte, die als Parameter an den Zustandsautomaten states() übergeben werden. Das Ergebnis dieser Funktion kann ausschließlich in der Funktion states() verarbeitet werden.

  • sx: ist der nächster Zustand, sofern die Bedingung der Transition erfüllt ist. Fehlt sx, führt die Transition in den jeweils aktiven Ausgangszustand zurück ohne diesen jedoch neu zu starten. sx kann auch aus einer Berechnung oder einer Variablen stammen. Falls sx keinen bekannten Zustand bezeichnet, wird der Ersatzwert sFail verwendet.

  • cond: Bedingung für den Zustandsübergang, def.: true

  • tBegin, tEnd: Zeitintervall bezogen auf die Aktiv-Zeit des Zustands, in dem die Bedingung ausgewertet wird. Def.: [tBegin,tEnd[=[0,[[t_{Begin}, t_{End}[ = [0, \infty[

states(..., transit({...})        // Transition in den Ausgangszustand
, transit(sx, {...})    // Transition nach sx
, transit(sx, cond)     // ...mit dynamischer Bedingung
, transit(sx, cond, tBegin)        // ...gültig ab Zeitpunkt
, transit(sx, cond, tBegin, tEnd)  // ...gültig im Zeitintervall
, ...);
// Optionale Konfiguration für alle Varianten, sofern nicht
// explizit gefordert
transit(..., { tBegin: <dbl>
, tEnd: <dbl>
, sFail: <var>
, nMax: <int>
, nVar: <str>
, actVar: <str>
, edge: <int>
, prio: <int>
})
EigenschaftWertBeschreibung
tBegin<bool>Zeitpunkt in Sekunden bezogen auf die Aktiv-Zeit des Zustands, ab dem die Bedingung ausgewertet wird, def.: 0.0
tEnd<uint>Zeitpunkt in Sekunden bezogen auf die Aktiv-Zeit des Zustands, bis zu dem die Bedingung ausgwertet wird, def.: \infty
sFail<var>Ersatzbezeichner / Zielzustand, falls sx keinen gültigen Zustand bezeichnet
nMax<int>maximale Anzahl an Aktivierungen in Folge (Schleifenzähler), wird zurückgesetzt, sofern der Zustand mit einer beliebigen anderen Transition verlassen wird.
nVar<str>Der Schleifenzähler kann in der bezeichneten Variable veröffentlicht werden und wird mit Auslösung der Transition aktualisiert.
actVar<str>Solange eine Transition auslöst, wird auf der bezeichneten Variable true ausgegeben.
edge<int>bestimmt, ob die Transition statisch (0), mit posedge (1) oder negedge (-1) der Bedingung ausgelöst wird.
prio<int>Optionale Priorität, falls mehrere Transitionen gleichzeitig auslösen. Prinzipiell gewinnt in der Reihenfolge der Definition die erste mit der höchsten prio-Stufe.

Beispiele

Footnotes

  1. Die schnellste Zeitkonstante des Prozesses (T0=12πf0T_0 = \frac{1}{2\pi f_0}) sollte das 10 - 15 fache der Abtastzeit des Steuerungs-/Regelungssystems sein.