Simulación de un lazo de control con ModelingToolkit
control de procesos
julia
Autor/a
runjaj
Fecha de publicación
22 de mayo de 2023
En la entrada anterior dedicada al cálculo numérico de la transformada de Laplace decía que es preferible simular las ecuaciones diferenciales directamente a utilizar el método de Talbot para estimar numéricamente la transformada de Laplace. La última opción solo la usaría para problemas sencillos en los que estamos trabajando con funciones de transferencia y nos puede dar pereza reescribir el problema.
Me quedé con ganas de plantear la simulación de esa entrada utilizando las ecuaciones diferenciales y métodos numéricos más potentes.
Planteamiento del modelo matemático
El sistema a controlar es el lazo de control por retroalimentación siguiente:
Código
usingLaTeXStrings, TikzPicturesTikzPicture(L"""\draw [draw=black, fill=yellow!10, very thick, dashed] (1.5,-1) rectangle ++(5,2.5) node [below, xshift=-2.5cm]{\textbf{Sistema de control}};;\node[rectangle, align=right] (entrada) {$y_{sp}(t)$};\node[circle, , very thick, draw, right=1.5cm of entrada, minimum size=0.5cm] (comp) {};\node[rectangle, very thick, draw, right=1.5cm of comp, minimum size=1.5cm] (control) {Controlador};\node[rectangle, very thick, draw, right=1.5cm of control, minimum size=1.5cm, align=center] (efc) {Elem. final\\de control};\node[rectangle, very thick, draw, right=1.5cm of efc, minimum size=1.5cm] (proc) {Proceso};\node[rectangle, align=left, right=1.5cm of proc] (salida) {$y(t)$};\node[rectangle, very thick, draw, below=0.75cm of efc, minimum size=1.5cm] (medidor) {Medidor};\node [circle, right=.75cm of proc] (output) {};\draw [->, very thick] (entrada) -- node[above, pos=0.95] {{$+$}} (comp);\draw [->, very thick] (comp) to node[above] {$\varepsilon(t)$} (control);\draw [->, very thick] (control) to node[above]{$c(t)$} (efc);\draw [->, very thick] (efc) to node[above]{$f(t)$} (proc);\draw [->, very thick] (proc) -- (salida);\draw [->, very thick] (output.west) |- (medidor);\draw [->, very thick] (medidor) -| node[pos=0.3, above right] {$y_m(t)$} node[pos=0.99, left] {{$-$}} (comp) ;""", options=raw"font=\sffamily", preamble=raw"\usetikzlibrary{positioning}", width="400px")
El comparador viene descrito por la siguiente ecuación:
\[\varepsilon(t) = y_{sp}(t)-y_m(t)\]
El controlador es un controlador proporcional:
\[c(t) = K_c \varepsilon(t)\]
Nota
Estamos utilizando variables de desviación sobre el estado inicial para que todas las condiciones iniciales sean 0.
La válvula, proceso y medidor vienen definidos por procesos de primer orden. Los sistemas de primer orden vienen descritos por una ecuación diferencial de primer orden del tipo:
Los parámetros de los componentes el lazo de contro son:
Elemento
Ganancia (\(K\))
Cte. de tiempo (\(\tau\))
Válvula
2
1
Proceso
4
5
Medidor
1
0.5
Escritura de las ecuaciones en ModelingTookit
Para resolver el sistema de ecuaciones anterior con Julia utilizaremos ModelingToolkit.jl. Es una auténtica maravilla, potente y sencillo de utilizar.
Empezaremos cargando las librerías a utilizar:
usingModelingToolkit, OrdinaryDiffEq, Plots
OrdinaryDiffEq es la librería de resolución numérica de ecuaciones diferenciales que utilizará ModelingToolkit para resolver nuestro sistema de ecuaciones.
A continuación, vamos a definir con el macro @variables la variable independiente, el tiempo, y las funciones que componen nuestro sistema:
@variables t err(t) c(t) f(t) y(t) ym(t) ysp(t)
\[ \begin{equation}
\left[
\begin{array}{c}
t \\
\mathrm{err}\left( t \right) \\
c\left( t \right) \\
f\left( t \right) \\
y\left( t \right) \\
\mathrm{ym}\left( t \right) \\
\mathrm{ysp}\left( t \right) \\
\end{array}
\right]
\end{equation}
\]
También definiremos el único parámetro que va a tener nuestro modelo matemático, la ganancia del controlador \(K_c\):
\[ \begin{align}
\mathrm{ysp}\left( t \right) =& 1 \\
\mathrm{err}\left( t \right) =& - \mathrm{ym}\left( t \right) + \mathrm{ysp}\left( t \right) \\
c\left( t \right) =& Kc \mathrm{err}\left( t \right) \\
\frac{\mathrm{d} f\left( t \right)}{\mathrm{d}t} =& 2 c\left( t \right) - f\left( t \right) \\
\frac{\mathrm{d} y\left( t \right)}{\mathrm{d}t} =& \frac{1}{5} \left( - y\left( t \right) + 4 f\left( t \right) \right) \\
\frac{\mathrm{d} \mathrm{ym}\left( t \right)}{\mathrm{d}t} =& 2 \left( - \mathrm{ym}\left( t \right) + y\left( t \right) \right)
\end{align}
\]
El siguiente paso es definir el modelo matemático a resolver:
@named model =ODESystem(eqs, t)
\[ \begin{align}
\frac{\mathrm{d} f\left( t \right)}{\mathrm{d}t} =& 2 c\left( t \right) - f\left( t \right) \\
\frac{\mathrm{d} y\left( t \right)}{\mathrm{d}t} =& \frac{1}{5} \left( - y\left( t \right) + 4 f\left( t \right) \right) \\
\frac{\mathrm{d} \mathrm{ym}\left( t \right)}{\mathrm{d}t} =& 2 \left( - \mathrm{ym}\left( t \right) + y\left( t \right) \right) \\
\mathrm{ysp}\left( t \right) =& 1 \\
\mathrm{err}\left( t \right) =& - \mathrm{ym}\left( t \right) + \mathrm{ysp}\left( t \right) \\
c\left( t \right) =& Kc \mathrm{err}\left( t \right)
\end{align}
\]
Queda un sistema de 6 ecuaciones, pero que ModelingToolkit tiene la capacidad de simplificar algebraicamente nuestras ecuaciones:
sys =structural_simplify(model)
\[ \begin{align}
\frac{\mathrm{d} f\left( t \right)}{\mathrm{d}t} =& 2 c\left( t \right) - f\left( t \right) \\
\frac{\mathrm{d} y\left( t \right)}{\mathrm{d}t} =& \frac{1}{5} \left( - y\left( t \right) + 4 f\left( t \right) \right) \\
\frac{\mathrm{d} \mathrm{ym}\left( t \right)}{\mathrm{d}t} =& 2 \left( - \mathrm{ym}\left( t \right) + y\left( t \right) \right)
\end{align}
\]
Reduce nuestro modelo matemático a la mitad de ecuaciones. Ya solo nos queda dar valor a la ganancia del controlador para poder realizar la simulación:
p = [Kc =>0.5]
1-element Vector{Pair{Num, Float64}}:
Kc => 0.5
Resolución numérica del sistema de ecuaciones
Definimos los tiempos para los que deseamos realizar la simulación:
tspan = (0.0, 20.0)
(0.0, 20.0)
Con todos estos elementos ya podemos definir el problema a resolver numéricamente:
prob =ODEProblem(sys, u0, tspan, p, jac=true)
ODEProblem with uType Vector{Float64} and tType Float64. In-place: true
timespan: (0.0, 20.0)
u0: 3-element Vector{Float64}:
0.0
0.0
0.0
Con jac=true estamos indicando a ModelingToolikt que calcule el jabobiano del sistema algebraicamente.
Finalmente resolvemos numéricamente las ecuaciones:
No hay ningún problema si queremos representar otras variables:
plot(sol, idxs=[ysp, y, c], size=(500,400))
Para acabar vamos a comparar las diferentes respuestas para los siguientes valores de ganancia del controlador: 0.01, 0.1, 1 y 2.5.
Como el problema a resolver numéricamente prob ya está creado, no es necesario que repitamos el cálculo. Podemos modificar el problema con la instrucción remake. Como vamos a repetir la simulación para varios valores de \(K_c\), definiremos una función:
functionsimul(Kc_val) p = [Kc => Kc_val] newprob =remake(prob; p=p)solve(newprob, Tsit5())end
simul (generic function with 1 method)
Con un bucle podemos representar todas las soluciones en un mismo gráfico para poder compararlas:
plot(size=(500,400))for i in [0.01, 0.1, 1, 2.5]plot!(simul(i), idxs=[y], label=i)endplot!()
Finalmente comprobamos que no tenemos los problemas de estabilidad del método numérico cuando el tiempo es un poco largo:
plot(simul(3.5), size=(500,400))
Conclusiones
Hemos visto que ModelingToolkit nos permite simular un lazo de control de manera muy simple gracias al uso que hace del cálculo simbólico y de los mejores algoritmos disponibles en la resolución de ecuaciones diferenciales.
Hemos planteado el sistema de ecuaciones diferenciales, lo que no ha resultado difícil. Una manera alternativa, quizás más sencilla, es utilizar la ModelingToolkitStandardLibrary que nos permitirá de manera muy simple definir elementos de primer orden, segundo orden, controladores PID, etc., pero esto queda para otro día.