Problemstellung
Es ist ohne Weiteres möglich ein zeitdiskretes Signal (Wertefolge, die
in gleichmäßigen Abständen gemessen wird), zu differenzieren. Meistens
allerdings braucht man diese Ableitung aber "sofort" also "on-the-fly"
und nicht erst, wenn das komplette Signal eingelesen ist.
Hier also ein kleines How-To, wie man sich ein Differenzierglied
beliebiger Genauigkeit baut.
Theorie
Die Theorie erfordert Grundlagenwissen Regelungstechnik & Mathematik:
Laplace-Transformation, z-Transformation, evtl. Tustin-Transformation,
Übertragungsfuntkion, realisierbare Übertragungsglieder,
Approximationsverfahren (speziell Padé-Approximation), ...
und wird möglichst klein gehalten.
Namenskonvention
Der Algorithmus zur Berechnung der Ableitung wird auf ein periodisch
digitalisiertes Analogsignal angewandt. Diese Periode hat den Wert T.
Durch einen großen Algorithmus steigt vermutlich T, da die nötige
Berechnungszeit steigt.
Das kleinste denkbare Differenzierglied lautet y[k] = 1/T(u[k] - u[k-1])
und wird hier nur kurz für die Namenskonvention betrachtet. y[k]
bezeichnet den Ausgang des Differenzierers, u[k] den aktuellen
Eingangswert. Der vorige Eingangswert u[k-1] muss in einer Variable
zwischengespeichert werden, die für den nächsten Schritt mit dem
aktuellen Eingangswert überschrieben werden kann. In Pseudocode:
1 | int u_k1 = 0;
|
2 | do
|
3 | {
|
4 | y = (u - u_k1)/T;
|
5 | u_k1 = u;
|
6 | }
|
Praxis
- Man wählt eine Ordnung n. Der Algorithmus wird 2n Speicherplätze für
Vergangenheitswerte benötigen.
- Man setzt den Wert für n in diese URL ein und lässt sich die
Padé-Approximation für ein Differenzierglied berechnen:
http://www.wolframalpha.com/input/?i=PadeApproximant[-Log[x],+{x,+1,+n}]
- dieser Bruch wird nun aufgelöst, dass er folgende Form hat:
, wobei b0 = 1 vorgegeben ist.
- dieser Bruch wird mit 1 gleichgesetzt und Nenner nach "Links"
multipliziert
- auf der Linken Seite bedeutet nun x^n soviel wie y[k-n], also den
Wert, der vor n Schritten am Ausgang lag.
x^(n-1) bedeutet demzufolge y[k-n+1].
x^1 bedeutet demzufolge y[k-1]
1 bedeutet demzufolge y[k] - die gesuchte Größe.
Genauso bedeutet auf der Rechten Seite x^n soviel wie u[k-n].
Links stehen also die Ausgangswerte, rechts die Eingangswerte
- nun einfach nur noch die vergangenen Ausgangswerte mit "minus" nach
rechts bringen und schon habt die Berechnungsvorschrift für eine
Ableitungsnäherung beliebiger Genauigkeit.
Beispiel n=4 - hoffe mal, ich hab mich nicht verrechnet:
1 | int u_k1 = 0;
|
2 | int u_k2 = 0; // nur Zwischenspeicher, kommt in Formel nicht vor.
|
3 | int u_k3 = 0;
|
4 | int u_k4 = 0;
|
5 | int y_k1 = 0;
|
6 | int y_k2 = 0;
|
7 | int y_k3 = 0;
|
8 | int y_k4 = 0;
|
9 | do
|
10 | {
|
11 | y = (int)(5.0/6.0*(5*u + 32*u_k1 - 32*u_k3 - 5*u_k4) - 16*y_k1 - 16*y_k2 - 16*y_k3 - y_k4);
|
12 | u_k4 = u_k3;
|
13 | u_k3 = u_k2;
|
14 | u_k2 = u_k1;
|
15 | u_k1 = u;
|
16 | y_k4 = y_k3;
|
17 | y_k3 = y_k2;
|
18 | y_k2 = y_k1;
|
19 | y_k1 = y;
|
20 | }
|
Weiterführendes
Aus einer Beliebigen Übertragungsfunktion G(s) lässt sich G(x) gewinnen,
indem man einfach jedes auftretende s durch die gewählte
Padé-Approximation ersetzt. Das Umformen und Auflösen könnte hier
allerdings Arbeit bedeuten. Evtl eine Mathetool verwenden?
ToDo
- Ermitteln, bis zu welcher Ordnung sich der Genauigkeitsgewinn lohnt,
da er ja Rechenzeit kostet, und damit T wächst. Im schlimmsten Fall
bleibt die Realisierung in PLD als Ausweg. Dann steigt nämlich "nur" die
Komplexität und nicht T. Außerdem liegt irgendwann der
Genauigkeitsgewinn außerhalb der Wahrnehmbarkeit, wenn man nicht den
Variablentyp ändert.
- Testen der Vorgehensweise in der Praxis = Fehlersuche... :/