Einstieg in die Regelungstechnik mit Python

Fachbuch von Hans-Werner Philippsen

Beobachterentwurf

Für das nachfolgende System 3. Ordnung, bestehend aus el. Widerständen und Kondensatoren, liegt ein Zustandsraummodell vor.

Die Bauteile genügen den Bedingungen:

\[ R_1 = R_2 = R_3= R \quad R_4 = R_e \quad C_1 = C_2 = C_3 = C \quad \quad T = RC \]

Das Zustandsraummodell der RC-Schaltung ist:

\[ \left[ \begin{array}{c} \dot{x}_1 \\ \dot{x}_2 \\ \dot{x}_3 \end{array} \right] = \begin{bmatrix} -(2/T+1/(CR_e)) & 1/T & 0\\ 1/T & -(2/T+1/(CR_e) ) & 1/T \\ 0 & 1/T & -(1/T+1/(CR_e))\end{bmatrix} \left[ \begin{array}{c} x_1 \\ x_2 \\ x_3\end{array} \right] + \left[ \begin{array}{c} 1/T \\ 0 \\ 0\end{array} \right] u_{ein}\]

Das Modell wird in Python mit Bauteildaten wie folgt dargestellt

import numpy as np
import control as ct
import matplotlib.pyplot as plt

# Regelstrecke in Zustandsraumdarstellung
C = 100e-6    #   Kond
R = 10e3        # Widerstand 1, 2 und 3
Re = 1200e3        #  Rein ADW 1,2M
R4 = 100e3        # Widerstand 4
T = R*C
T2 = C*Re 
Am  = np.array([[-(2/T + 1/T2),  1/T, 0],
                [1/T,  -(2/T + 1/T2), 1/T],
                [0, 1/T, -(1/T + 1/(Re*C))]])
bm  = np.array([[ 1/T],[0],[0]])
cmt  = np.array([ [0], [0], [1]]) # transponierter Ausgangsvektor für Ackermannformel
CC = np.identity(3)
D = np.zeros((3,1))
RC3 = ct.ss(Am, bm, CC, D, name='rc3',inputs='u', outputs=['y1','y2','y3'])

Der Entwurf des Beobachters setzt die Vorgabe der Dynamik voraus (siehe im Buch ab S. 256).

# Beobachterentwurf
p = -1/0.7  # Vorgabe Dynamik/Pole
# Rückkoppelvektor mit Hilfe der Formel von Ackermann berechnen
h = ct.acker(Am,cmt,[p,p,p])
# Bildung Eingangsmatrix Beobachter
bo = np.zeros((3,2))
bo[:,0]=bm.T
bo[:,1]=h
DD = np.zeros((3,2))
#Beobachtermodell
bmod = ct.ss(Am, bo, CC, DD, name='beob',inputs=['u','e'], outputs=['x1','x2','x3'])

Für die Simulation werden Strecke und Beobachter zusammengeführt:

# Bildung Fehlersignal
sumblk = ct.summing_junction(inputs=['y3', '-x3'], output='e')

# Strecke mit Beobachter
Sb = ct.interconnect([RC3,sumblk, bmod
                      ], inplist='u', outlist=['y1','y2','y3','x1','x2','x3','e'])

t=np.arange(0,30,0.05)
ww = np.ones(len(t))
x0 = [0.4,0.4,0.4,0,0,0]   # Vorgabe Anfangswerte
t, yy = ct.input_output_response(Sb, t, ww,x0,solve_ivp_method='BDF')
plt.figure()
plt.plot(t,yy.T)
plt.title('Beobachter für RC3R')
plt.xlabel('t [s]'); plt.ylabel('alle x')    
plt.grid()
#plt.figure() # plot step x ohne Beobachter
#plt.plot(t,y[:,0,:].T)
# Diskretisierung Beobachter
modd = ct.c2d(bmod,0.1)
print(modd)

Das nachfolgende Bild zeigt die Sprungantwort aller Zustände der Strecke mit Beobachter. Die Strecke wurde mit gleichen Anfangswerten versehen (0,4), der Beobachter (Anfangswerte alle 0) schätzt aber nach ca. 5 Sek. alle Zustände korrekt. Die Vorgabe einer schnelleren Beobachterdynamik (z.B. mit p =-1/0,4) verbessert das Verhalten deutlich.

Ein Beobachter wird in der Praxis nicht so glatte Zeitverläufe aufweisen, jedoch die Zustände gut schätzen können. Das folgende Beispiel zeigt die gemessenen Werte des RC-Netzwerks und die Reaktion des Beobachters, der mit microPython auf einem esp32 realisiert wurde. Die Zustände des RC-Netzwerks starten bei ca. 0,4 Volt, die Beobachterzustände starten bei 0 Volt.

Theme von Anders Norén