Diseño del sistema de control del pédulo invertido#
Seguimos con el ejemplo de teoría, pero con un pequeño cambio:
w0=2
A=[[0,1],[-w0**2,0]]
B=[[0],[1]]
C=[1,0]
D=0
pendulo=ctrl.ss(A,B,C,D)
pendulo
\[\begin{split}
\left(\begin{array}{rllrll|rll}
0\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&1\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&0\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}\\
-4\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&0\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&1\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}\\
\hline
1\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&0\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&0\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}\\
\end{array}\right)
\end{split}\]
Obtención de la ley de control#
K=ctrl.acker(pendulo.A,pendulo.B,[-2*w0,-2*w0])
K
array([[12., 8.]])
Diseño del estimador completo#
L=ctrl.acker(pendulo.A.T,pendulo.C.T,[-4*w0,-4*w0]).T
L
array([[16.],
[60.]])
np.linalg.eigvals(pendulo.A-pendulo.B@K)
array([-4., -4.])
np.linalg.eigvals(pendulo.A-L@pendulo.C)
array([-8., -8.])
Definimos el sistema compensador ( entrada \(y\), salida \(u\))#
s=pendulo
Acomp=s.A-s.B@K-L@s.C
Bcomp=L
Ccomp=-K
comp=ctrl.ss(Acomp,Bcomp,Ccomp,0)
comp
\[\begin{split}
\left(\begin{array}{rllrll|rll}
-16\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&1\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&16\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}\\
-76\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&-8\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&60\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}\\
\hline
-12\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&-8\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}&0\phantom{.}&\hspace{-1em}&\hspace{-1em}\phantom{\cdot}\\
\end{array}\right)
\end{split}\]
np.linalg.eigvals(comp.A)
array([-12.+7.74596669j, -12.-7.74596669j])
Vemos que los polos del compensador son estables!
comp.zero()
array([-0.30952381+0.j])
Verificamos que los polos a lazo cerrado del sistema compensado son los adecuados:
sys_comp = ctrl.feedback(-s*comp)
sys_comp.pole()
array([-8.00000055+0.00000000e+00j, -7.99999945+0.00000000e+00j,
-4. +2.82767841e-07j, -4. -2.82767841e-07j])
Ahora verificamos que el sistema a lazo cerrado tiene efectivamente los polos donde se pretendía. Igualmente será necesario rediseñar para lograr un controlador que sea correcto.
Sistema completo.#
sys_completo = ctrl.connect(ctrl.append(s,comp),[[1,2],[2,1]],[1],[1,2])
t,y = ctrl.initial_response(sys_completo, X0=[1,0,0,0], T=np.linspace(0,3,1001))
Show code cell source
fig, ax = plt.subplots(2,1,figsize=(12,8))
ax[0].plot(t,y[0,:],label="sys completo")
ax[0].set_title('Respuesta al escalón en la referencia')
ax[0].set_xlabel("Tiempo")
ax[0].set_ylabel("Salida")
ax[0].grid()
ax[1].plot(t,y[1,:],label="sys completo")
ax[1].set_title('Respuesta al escalón en la referencia')
ax[1].set_xlabel("Tiempo")
ax[1].set_ylabel("Salida")
ax[1].grid()
fig.tight_layout()
np.linalg.eigvals(sys_completo.A)
array([-8.+6.17544035e-07j, -8.-6.17544035e-07j, -4.+1.20399686e-07j,
-4.-1.20399686e-07j])
Ubicación óptima de los autovalores del estimador#
B1=B
def conjugate_tf(G):
num = ctrl.tf(G).num[0][0]
den = ctrl.tf(G).den[0][0]
nume = [num[i]*((-1)**(len(num)%2+1-i)) for i in range(0, len(num))]
dene = [den[i]*((-1)**(len(den)%2+1-i)) for i in range(0, len(den))]
return ctrl.tf(nume,dene)
aux1 = ctrl.ss(A,B1,C,D)
aux2 = conjugate_tf(aux1)
G_srle = ctrl.tf(aux1)*aux2
ctrl.rlocus(G_srle, xlim=[-8,8], ylim=[-10,10]); #aumento los límites para ver la zona donde quiero ubicar el polo
plt.gcf().set_size_inches(8,6)
k=12000 # lo busco haciendo clcik sobre las lineas del root locus simétrico
r,k = ctrl.rlocus(G_srle, kvect=[8000],Plot=False)
r
/usr/share/miniconda/lib/python3.11/site-packages/control/rlocus.py:132: FutureWarning: 'Plot' keyword is deprecated in root_locus; use 'plot'
warnings.warn("'Plot' keyword is deprecated in root_locus; "
array([[-6.53957633-6.83857138j, -6.53957633+6.83857138j,
6.53957633-6.83857138j, 6.53957633+6.83857138j]])
rsel = r[np.real(r)<0]
rsel
array([-6.53957633-6.83857138j, -6.53957633+6.83857138j])
L = ctrl.place(pendulo.A.T, pendulo.C.T, rsel).T
L
array([[13.07915266],
[85.53211714]])
comp_srl = ctrl.ss(s.A-s.B@K-L@s.C, L, -K, 0)
comp_srl.pole()
array([-10.53957633+9.75103426j, -10.53957633-9.75103426j])
sys_completo_srl = ctrl.connect(ctrl.append(s,comp_srl),[[1,2],[2,1]],[1],[1,2])
t_srl, y_srl = ctrl.initial_response(sys_completo_srl, X0=[1,0,0,0], T=np.linspace(0,3,1001))
L
array([[13.07915266],
[85.53211714]])
K
array([[12., 8.]])
Show code cell source
fig, ax = plt.subplots(2,1,figsize=(12,8))
ax[0].plot(t,y[0,:],label="sys completo 2do orden dominante")
ax[0].plot(t_srl,y_srl[0,:],label="sys completo SRL")
ax[0].set_title('Respuesta al escalón en la referencia')
ax[0].set_xlabel("Tiempo")
ax[0].set_ylabel("Salida")
ax[0].grid()
ax[1].plot(t,y[1,:],label="sys completo 2do orden dominante")
ax[1].plot(t_srl,y_srl[1,:],label="sys completo SRL")
ax[1].set_title('Respuesta al escalón en la referencia')
ax[1].set_xlabel("Tiempo")
ax[1].set_ylabel("Salida")
ax[1].grid()
fig.tight_layout()