Introdução a Simulação de Controle de Sistemas com Python — Parte 02

Oséias Farias
Editorial 20 21
Published in
10 min readOct 26, 2021

Agora que fizemos uma revisão sobre os temas relativos à simulação de Controle de Sistemas na Parte 01, estamos prontos para escrever o código e entender o que cada linha significa.

FUNÇÃO DE TRANSFERÊNCIAS DOS SUBSISTEMAS

As Funções de Transferências dos sub-sistemas do sistema que queremos controlar, são:

Modelo do Circuito RC:

valores dos componentes:

  • Capacitor: C=10μF
  • Resistor: R=20kΩ

Com esses valores, a Função de Transferência H(s) fica da seguinte forma:

Sensor:

A Função de Transferência P(s) do sensor para esse Sistema de Controle por Realimentação e dada por:

Controlador:

Já para o Controlador, usaremos apenas a parte proporcional do controlador PID, assim temos que a Função de Transferência C(s) e dada por:

Essas são as Funções de Transferência necessárias para codificarmos nossa simulação.

ESCREVENDO O CÓDIGO PARA SIMULAÇÃO

Antes de iniciarmos a codificação da simulação, instalaremos as bibliotecas necessárias.

Instalação das Bibliotecas via pip

Abra seu Terminal, certifique-se de ter instalado o Python3 na sua máquina. Feito isso, copie o seguinte código no seu terminal:

python -m pip install -U pip
pip install control
python -m pip install -U matplotlib
pip install numpy

Código de Simulação — Resposta ao Degrau Unitário

Importando as Bibliotecas necessárias para a simulação

Crie um arquivo .py, por exemplo, simu_circuito_rc.py e importe as bibliotecas digitando as seguintes linhas de código:

import control as ctl
import matplotlib.pyplot as plt
import numpy as np
plt.style.use("seaborn")
# %matplotlib inline # use no Jupyter Notebook, Google Colab

Logo abaixo das bibliotecas importadas, digite as seguintes linhas de código, elas são as constantes relativas aos valores de componentes e ao tempo de simulação.

R = 20.0e3         # Resistência do Resistor
C = 10.0e-6 # Capacitância do Capacitor
tau = R*C # Multiplicação de R POR C.
Temp_simu = 2.0 # Tempo de simulação.

Agora criaremos uma função em Python, para ficar melhor de realizar as simulações com diferentes valores de K_p. A linha de código abaixo mostra a estrutura de uma função em Python.

Código:

import control as ctl 
import matplotlib.pyplot as plt
import numpy as np
plt.style.use("seaborn")# Use no Jupyter notebook, colab
# %matplotlib inline
# Variáveis da Simulação
R = 20.0e3
C = 10.0e-6
tau = R*C
Temp_simu = 2.0
# Função que calcula a resposta ao degrau
def Simulacao_RC(K_p = 3.0):
# Cria a Função de Transferência em Malha Aberta
numerador = [1/tau]
denominador = [1.0, 1/tau]
H_s = ctl.tf(numerador, denominador)
#print(f"\n\n> Função de Transferência em Malha Aberta:\n {H_s}")
# Cria a Função de Transferência do Controlador
C_s=ctl.tf([K_p],[1.])
#print(f"\n> Função de Transferência do Controlador:\n {C_s}")
# Cria a Função de Transferência do Sensor
P_s=ctl.tf([1.],[1.])
# Função de Transferência em Malha Fechada
G_s=ctl.series(C_s, H_s);
G1_s=ctl.feedback(G_s, P_s, sign=-1);
# print(f"\n> Função de Transferência em Malha fechada:\n {G1_s}")
# Calcula a resposta ao Degrau Unitário
T_mf, yout_mf = ctl.step_response(G1_s, Temp_simu)
# Plotando o degrau unitário
Temp_deg = np.linspace(-0.2, Temp_simu, 1000)
degrau = np.ones_like(Temp_deg)
degrau[Temp_deg < 0] = 0
return T_mf, yout_mf, Temp_deg, degrau, K_p
# Função que plota 3 gráficos com K_p diferentes para a resposta ao degrau
def prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x):
plt.subplot(1, 3, x)
plt.plot(T_mf, yout_mf, linewidth = 1.2)
plt.plot(Temp_deg, degrau, color = "r", linestyle = "--",
linewidth = 1.2)

# Customizando a figura com Titulo, Títulos nos eixos, Legenda e
Grid
plt.title("Circuito RC - Resposta ao Degrau em Malha Fechada",
fontweight="bold", fontsize = 10)
plt.ylabel("Tensão no Capacitor (V)", fontweight="bold",
fontsize = 8)
plt.xlabel("Tempo (s)", fontweight="bold", fontsize = 8)
plt.legend(["Resposta ao Degrau", "Degrau Unitário"],
fontsize = 8)
if __name__ == "__main__":

# Plotando a resposta ao Degrau usando o metodo plt.plot() da
biblioteca matplotlib
plt.figure(figsize=(15, 7))
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = 1)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 1)
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = 4)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 2)
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = 8)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 3)
plt.show()

Saída:

Plotagem via Notebook

Explicação do Código

def Simulacao_RC(K_p = 3.0):

A linha acima é uma função que comporta o código de simulação, assim podemos fazer varias simulações modificando o valor de K_p para diferentes valores e ver como o sistema se comporta com essas mudanças.

Criando a função de transferência usando a Biblioteca Control-Python

Onde:

  • tau = RC
# Cria a Função de Transferência em Malha Aberta
numerador = [1/tau] # Numerador da função de transferência
denominador = [1.0, 1/tau] # Denominador da função de transferência
H_s = ctl.tf(numerador, denominador)

A Biblioteca Control-Python tem um método que constrói a Função de Transferência de um sistema no domínio de Laplace, o código acima demostra como funciona a construção de uma Função de Transferência usando esse método.

Ele recebe dos parâmetros, sendo o primeiro o numerador e o segundo o denominador da função de transferência, assim é possível criar uma função de transferência no domínio de Laplace. que tem como resultado a seguinte equação:

Função de Transferência do Controlador

# Cria a Função de Transferência do Controlador
C_s=ctl.tf([K_p],[1.])

A Função de Transferência para o nosso controlador em questão, é um ganho proporcional, ou seja, apenas uma constante, no entanto, a Biblioteca Control-python sempre precisa receber os dois parâmetros — o numerador e denominador — assim, podemos escrever o denominador valendo 1, já que a divisão por um, não altera o valor dividido.

K_p é a variável que passamos como argumento na função Simulacao_RC(K_p = 3.0), logo, podemos colocar diferentes valores em k_p e observar como o sistema se comporta para esses valores.

Exemplo:

Função de Transferência do Sensor

O sensor é unitário, então sua função de transferência é 1. Usando a Biblioteca Control-python sua escrita fica da seguinte forma.

# Cria a Função de Transferência do Sensor
P_s = ctl.tf([1.],[1.])

Como você pode perceber, a escrita usando essa biblioteca é um pouco diferente do que estamos acostumados, mas o resultado é igual, já que 1/1=1.

FUNÇÃO DE TRANSFERÊNCIA EM MALHA FECHADA OU POR REALIMENTAÇÃO

Agora que temos as funções de transferências, podemos conectar a função do controlador com a do sistema usando o método ctl.series() da e depois realimentar o sistema com o sinal do sensor usando o método ctl.feedback().

# Função de Transferência em Malha FechadaG_s=ctl.series(C_s, H_s);
G1_s=ctl.feedback(G_s, P_s, sign=-1);

O método ctl.series() recebe as funções que vão ser conectadas em série, no nosso caso C_s e H_s e o método ctl.feedback() recebe a função gerada pelo método anterior e a função do sensor que será a realimentação. O terceiro parâmetro é se o sinal realimentado é positivo ou negativo, geralmente esse sinal de realimentação é negativo.

Obtida a Função em Malha Fechada, agora podemos usá-la para simular o comportamento do nosso sistema usando como exemplo o sinal degrau. Para isso, usaremos outro método da Biblioteca Control-python ctl.step_response() que recebe a Função em Malha Fechada encontrada na etapa anterior, e o tempo para simulação, após a simulação esse método retorna duas matrizes onde a primeira corresponde aos valores de simulação e a segunda aos tempos para cada instante simulado.

# Calcula a resposta ao Degrau UnitárioT_mf, yout_mf = ctl.step_response(G1_s, Temp_simu)

Gerando valores usando o Numpy para posterior plotagem de degrau unitário.

# Plotando o degrau unitárioTemp_deg = np.linspace(-0.2, Temp_simu, 1000)
degrau = np.ones_like(Temp_deg)
degrau[Temp_deg < 0] = 0

por fim, a função def Simulacao_RC(K_p = 3.0): após ser executada retorna os valores avaixo:

return T_mf, yout_mf, Temp_deg, degrau, K_p

FUNÇÃO PARA PLOTAR OS GRÁFICOS

Agora, tendo esses valores de simulação, podemos plotar o gráfico, e para isso criaremos uma função.

# Função que plota 3 gráficos com K_p diferentes para a resposta ao degraudef prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x):
#
# CÓDIGO PARA PLOTAGEM VEM AQUI ....

Essa função tem 6 parâmetros, sendo eles( T_mf, yout_mf, Temp_deg, degrau, K_p, x )

Onde:

  • T_mf: Matriz contendo os instantes de tempo de simulação retornado pela função Simulacao_RC.
  • yout_mf: Matriz retornada pela função Simulacao_RC com os valores simulados em cada instante de tempo T_mf
  • Temp_deg: Matriz com os valores de tempo gerados para plotar o degrau unitário também retornada pela função Simulacao_RC
  • degrau: Matriz com os valores gerados para plotar o degrau unitário também retornada pela função Simulacao_RC
  • K_p: Esse é o valor do ganho do controlador proporcional e é usado para colocar no título do gráfico.
  • x: É usado para criar um ID para o sub-gráfico

Tendo definido o significado dos parâmetros acima, agora entenderemos o código da função.

plt.subplot(1, 3, x)

O método plt.subplot() é usado para plotar vários gráficos em uma mesma figura, no nosso caso, vamos plotar 3 sub-gráficos um ao lado do outro; Dessa forma, os parâmetros que devemos usar para indicar essa configuração são três.

O primeiro indica a quantidade de linhas, no nosso caso é uma, a quantidade de colunas, no nosso caso são 3, e, por último, um identificador único para cada sub-gráfico, no nosso caso o sub-gráfico 1 terá o ID 1, o sub-gráfico 2 ID 2 e o sub-gráfico 3 ID 3.

plt.plot(T_mf, yout_mf, linewidth = 1.2)

O método plt.plot(argumento1, argumento2 …) recebe no primeiro argumento os valores de tempo retornados pela simulação, já o segundo recebe os valores de simulação, linewidth = 1.2 muda a espessura da linha do gráfico.

plt.plot(Temp_deg, degrau, color = "r", linestyle = "--", linewidth = 1.2)

O código acima plota o degrau unitário, na cor vermelha.

# Customizando a figura com Titulo,  Títulos nos eixos, Legenda e Gridplt.title("Circuito RC - Resposta ao Degrau em Malha Fechada", fontweight="bold", fontsize =  17)
plt.ylabel("Tensão no Capacitor (V)", fontweight="bold", fontsize = 14)
plt.xlabel("Tempo (s)", fontweight="bold", fontsize = 14)
plt.legend(["Resposta ao Degrau", "Degrau Unitário"], fontsize = 14)
#plt.grid()
plt.show() # Plota o gráfico

O código acima é usado para nomear a figura, os eixos e os sub-gráficos.

SIMULAÇÃO

Com essas duas funções podemos fazer a simulação do nosso sistema para diferentes valores de K_p. Nesse casso vamos usar três valores diferentes para nosso controlador proporcional.

# Plotando a resposta ao Degrau usando o metodo plt.plot() da biblioteca matplotlibplt.figure(figsize=(25, 7))# SIMULAÇÃO 01
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = 1)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 1)
# SIMULAÇÃO 02
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = 4)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 2)
# SIMULAÇÃO 02
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = 8)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 3)# PLOTA OS SUB-GRÁFICOS GERADOS EM UMA MESMA FIGURA
plt.show()

Saída:

Plotagem via Google Colab

OUTROS VALORES DE SIMULAÇÃO

# Plotando a resposta ao Degrau usando o metodo plt.plot() da biblioteca matplotlibplt.figure(figsize=(25, 7))
# SIMULAÇÃO 01
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = -3)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 1)
# SIMULAÇÃO 02
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = 0)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 2)
# SIMULAÇÃO 03
T_mf, yout_mf, Temp_deg, degrau, K_p = Simulacao_RC(K_p = 3)
prot_grafico(T_mf, yout_mf, Temp_deg, degrau, K_p, x = 3)
plt.show()

Saída:

Plotagem via Google Colab

Observe que para diferentes valores de K_p nosso sistema em malha fechada tem um comportamento diferente. Em outras palavras, nosso sistema pode ser estável ou instável dependendo do valor de K_p, mas essa análise de estabilidade fica para um próximo post.

CONCLUSÃO

O Python, portanto, é uma excelente ferramenta que possibilita uma gama ampla de pacotes e módulos auxiliadores no processo de análise e simulação de sistemas simples e complexos. Bibliotecas como a Control-python, Matplotlib, Numpy e muitas outras podem ser de grande utilidade para profissionais e estudantes; uma vantagem no uso de Python para simular e analisar sistemas é que diferentemente de softwares caros, seu uso é livre e gratuito.

CÓDIGO NO GITHUB E GOOGLE COLAB:

REFERÊNCIAS

  • Sinais e Sistemas Lineares. B.P. Lathi — Sinais e Sistemas Lineares (2006, Bookman).
  • Matplotlib, Site Oficial, 2020.

Disponível em: https://matplotlib.org/stable/users/installing.html. Acesso em: 14 de Out. de 2021.

  • Numpy, Site Oficial, 2020.

Disponível em: https://numpy.org/doc/stable/user/quickstart.html. Acesso em: 14 de Out. de 2021.

  • Python Control, Site Oficial, 2020.

Disponível em: https://python-control.readthedocs.io/en/0.8.3/intro.html. Acesso em: 14 de Out. de 2021.

  • Controlador proporcional integral derivativo, Wikipédia, a enciclopédia livre., 2020.

Disponível em: https://pt.wikipedia.org/wiki/Controlador_proporcional_integral_derivativo. Acesso em: 14 de Out. de 2021.

--

--