[PYTHON] [Introduction au PID] J'ai essayé de contrôler et de jouer ♬

Le contrôle PID semble être une technologie qui existe depuis longtemps. Donc, je l'ai soigneusement formulé et joué avec, donc je vais le résumer.

【référence】 ①PID controller ② [Contrôle PID](https://ja.wikipedia.org/wiki/PID%E5%88%B6%E5%BE%A1#:~:text=PID%E5%88%B6%E5%BE%A1 % EF% BC% 88% E3% 83% 94% E3% 83% BC% E3% 82% A2% E3% 82% A4% E3% 83% 87% E3% 82% A3% E3% 83% BC% E3 % 81% 9B% E3% 81% 84,% E6% 96% B9% E6% B3% 95% E3% 81% AE% E3% 81% 93% E3% 81% A8% E3% 81% A7% E3% 81% 82% E3% 82% 8B% E3% 80% 82)

Il peut être facilement représenté par le graphique suivant. À partir de la référence ci-dessus ① By Arturo Urquizo - PID_en.svg.png Ici, chaque quantité est définie comme suit.

\begin{align}
r(t)&;Montant cible\\
y(t)&;Après l'opération, la quantité actuelle de l'installation ou du processus cible\\
e(t)&=r(t)-y(t);Montant actuel-Résiduel calculé par montant cible\\
u(t)&=P+I+D;Montant de l'opération\\
          &;Opérations sur les usines et processus cibles\\
        &;La valeur du courant qui circule pour augmenter et diminuer la température et l'angle de fonctionnement de la poignée et de la vanne. ..\\
P&=K_pe(t);Contrôle proportionnel\\
I&=K_i\int_0^t e(\tau )d\tau;Contrôle intégral\\
D&=K_d\frac{de(t)}{dt};Contrôle différentiel\\
\end{align}

Ici, dans le cas du contrôle informatique, $ y (t) $ est une valeur discrète, il est donc préférable de définir le contrôle intégral et le contrôle différentiel par intégration numérique et différenciation numérique comme suit. Au moment d'échantillonnage $ t = t_n $, placer comme suit. La différenciation numérique peut être d'un ordre supérieur, mais ce qui suit peut être utilisé en considération de l'aspect pratique et de la réactivité.

\int_0^te(\tau)d\tau = \Sigma_{i=0}^ne(t_i)\Delta t\\
(\frac{de(t)}{dt})_{t_n}=\frac{e(t_n)-e(t_{n-1})}{\Delta t}\\
\Delta t = t_n-t_{n-1} ; const=Définir sur 1

Essayez de le déposer dans le code

Premièrement, les cibles de contrôle sont les suivantes. En d'autres termes, c'est une image du contrôle de la température des fours électriques.

def ufunc(M,u=0,t=0):
    M0=0.2
    m=0.05
    return M - m*(M-M0-u)

Le côté contrôleur considère le contrôle PID suivant. Une partie du code est basée sur ce qui suit. 【référence】 Essayez le contrôle PID avec Python

t = 100
params_list = [(0,0,0)]  #Kp,Ki,Définir Kd
for kp,ki,kd in params_list:
    Kp,Ki,Kd=kp,ki,kd
    M0 = 2
    M=M0
    goal = 1.00
    e = 0.00 
    e1 = 0.00 
    u=0
    es=0
    x_list = []
    y_list = []
    u_list = []
    x_list.append(0)
    y_list.append(M)
    u_list.append(u)
    for i in range(1,t,1):
        M1 = M
        e1 = e
        e = goal - y_list[i-1] #Écart (e)=Valeur objective (but)-Valeur actuelle
        es += e #Intégrer est un ajout
        u = Kp * e + Ki * es + Kd * (e-e1) #La différenciation est une soustraction
        M = ufunc(M,u,i) #Réponse de la cible
        x_list.append(i)
        y_list.append(M)
        u_list.append(u)
    plt.hlines([goal], 0, t, "red", linestyles='dashed') #L'objectif est affiché avec une ligne pointillée rouge
    plt.plot(x_list, y_list, color="b") #Le changement d'heure de la réponse est affiché en bleu
    plt.title('Kp={}, ki={}, kd={}'.format(Kp, Ki, Kd))
    #plt.plot(x_list, u_list, color="black") #La quantité d'opération est affichée en noir
    plt.ylim(-0.5, goal*2+0.2) #Réglage de la hauteur du graphique
    plt.pause(0.2)
    plt.savefig("output/Kp,Ki,Kd/imageKp{}Ki{}Kd{}M0{}.png ".format(Kp,Ki,Kd,M0))    
    plt.close()

Voir la réaction cible avec params_list = [(0,0,0)]

Lorsque t = 0, si M = 2 et la température ambiante est M0 = 0,2, elle s'approche progressivement de M = 0,2 comme suit. imageKp0.0Ki0.0Kd0.0M02dt1.png

Ce système est exprimé par l'équation suivante.

\frac{dM}{dt}=-m(M-M0)

La solution est

M=M0+(2-M0)e^{-mt}\\
t=Lorsque 0, M=2

Méthode de sensibilité limite de Ziegra Nichols

Voir la vibration critique de l'objet Selon Wikipedia, si Ki = Kp / Ti et Kd = Kp · Td, les paramètres optimaux sont déterminés comme suit par la méthode de sensibilité marginale de Ziegra Nichols.

Methode de CONTROLE Kp Ti Td
P 0.50Ku - -
PI 0.45Ku 0.83Tu -
PID 0.6Ku 0.5Tu 0.125Tu

Ici, Ku et Tu sont définis comme suit. «Le gain proportionnel Kp est progressivement augmenté à partir de 0, et lorsque la quantité de contrôle atteint la limite stable et que la vibration d'amplitude constante est maintenue, l'augmentation de Kp est arrêtée. Le gain proportionnel à ce moment est Ku (sensibilité limite). , Si le cycle de vibration est Tu Lorsque la vibration limite est calculée pour l'objet ci-dessus, elle est calculée comme Tu = 2,0 lorsque Ku = 39 comme indiqué ci-dessous. imageKp39.0Ki0.0Kd0.0M02dt1.png

Si vous réécrivez le tableau ci-dessus avec Ki, Kd,

Methode de CONTROLE Kp Ki Kd
P 0.50Ku - -
PI 0.45Ku 0.54Ku/Tu -
PID 0.6Ku 1.2Ku/Tu 3KuTu/40

résultat

En fait, si vous essayez avec les paramètres ci-dessus, Contrôle P Kp19.5Ki0.0Kd0.0M02dt1 imageKp19.5Ki0.0Kd0.0M02dt1.png Contrôle PI Kp17.55Ki10.57Kd0.0M02dt1 imageKp17.55Ki10.572289156626507Kd0.0M02dt1.png Contrôle PID Kp23.4Ki23.4Kd5.85M02dt1 imageKp23.4Ki23.4Kd5.85M02dt1.png En d'autres termes, le contrôle PID échoue pour une raison quelconque Cela semble être dû à l'erreur d'arrondi.

extension et recalcul de précision dt

Alors, étendez dt afin qu'il puisse être calculé par incréments arbitraires comme indiqué ci-dessous.

def ufunc(M,u=0,t=0,dt=1):
    M0=0.2
    m=0.05
    return M - m*(M-M0-u)*dt

t = 100
dt=0.1

Ku=39
Tu=2
params_list =[(0.5*Ku,0,0),(0.45*Ku,0.54*Ku/Tu,0),(0.6*Ku,1.2*Ku/Tu,3*Ku*Tu/40)]
for kp,ki,kd in params_list:
    Kp,Ki,Kd=kp,ki,kd
    ...
    for i in range(1,int(t/dt),1):
        ...
        e = goal - y_list[i-1] #Écart (e)=Valeur objective (but)-Dernière valeur réalisée
        es += e*dt
        u = Kp * e + Ki * es + Kd * ((e-e1)/dt )
        M = ufunc(M,u,i,dt)

        x_list.append(i*dt)
        y_list.append(M)
        u_list.append(u)
        ...
    plt.savefig("output/Kp,Ki,Kd,dt/imageKp{}Ki{}Kd{}M0{}dt{}.png ".format(Kp,Ki,Kd,M0,dt))    
    plt.close()

Ré-exécuté avec dt = 0.1, j'ai pu dessiner bien comme prévu. Contrôle PID Kp23.4Ki23.4Kd5.85M02dt0.1 imageKp23.4Ki23.4Kd5.85M02dt0.1.png Puisque le grand changement se termine à t = 0-10, il est maintenant possible de calculer le pas dt en détail, donc recalculons avec le pas dt = 0,01. Contrôle P Kp19.5Ki0.0Kd0.0M02dt0.01 imageKp19.5Ki0.0Kd0.0M02dt0.01.png Contrôle PI Kp17.55Ki10.57Kd0.0M02dt0.01 imageKp17.55Ki10.572289156626507Kd0.0M02dt0.01.png Contrôle PID Kp23.4Ki23.4Kd5.85M02dt0.01 imageKp23.4Ki23.4Kd5.85M02dt0.01.png

Reproduction graphique du contrôle PID

Essayez de reproduire le graphique suivant de la version anglaise de Wikipedia. Change_with_Ki.png Il semble que les conditions ne soient pas dessinées, donc lorsque je dessine différemment dans les conditions les plus probables, la dépendance Ki devient presque similaire dans les conditions suivantes.

def ufunc(M,u=0,t=0,dt=1):
    M0=0
    m=0.4
    return M + m*u*dt - m*(M-M0)*dt

Le calcul est basé sur les mêmes valeurs de paramètres que celles indiquées. Trois graphiques ont été dessinés en même temps avec une légende. La plage de dessin du graphique est ajustée.

t = 20
dt=0.01
params_list =[(1,0.5,1),(1,1,1),(1,2,1)]
for kp,ki,kd in params_list:
    Kp,Ki,Kd=kp,ki,kd
    M0 = 0
    M=M0
    goal = 1.00
    e = 0.00 
    e1 = 0.00 
    u=0
    es=0
    x_list = []
    y_list = []
    u_list = []
    x_list.append(0)
    y_list.append(M)
    u_list.append(u)
    for i in range(1,int(t/dt),1):
        M1 = M
        e1 = e
        e = goal - y_list[i-1] #Écart (e)=Valeur objective (but)-Dernière valeur réalisée
        es += e*dt
        u = Kp * e + Ki * es + Kd * ((e-e1)/dt )
        M = ufunc(M,u,i,dt)
        x_list.append(i*dt)
        y_list.append(M)
        u_list.append(u)
    plt.hlines([goal], 0, t, "red", linestyles='dashed') #L'objectif est affiché avec une ligne pointillée rouge
    plt.plot(x_list, y_list,label="Kp{}Ki{}Kd{}".format(Kp,Ki,Kd)) 
    plt.legend()
    plt.ylim(-0.1, 1.5) #Ajuster la hauteur du graphique
    plt.pause(0.2)
plt.savefig("output/Kp,Ki,Kd,dt/imageKp{}Ki{}Kd{}M0{}dt{}2.png ".format(Kp,Ki,Kd,M0,dt))    
plt.close()

D'autre part, la dépendance Kp peut être dessinée comme suit et elle ne peut pas être reproduite sans sélectionner les paramètres. imageKp1.6Ki1Kd1M00dt0.011.png Et la dépendance Kd semble être presque reproduite comme suit. imageKp1Ki1Kd2M00dt0.013.png

À propos de la cible de contrôle

Cette fois, nous fixons l'objectif de contrôle en imaginant la température du four électrique. Dans le contrôle réel, vous devez contrôler quelque chose de plus dynamique. Dans ce cas, je pense que cela peut être réalisé en réécrivant ufunc () introduit cette fois. De plus, en fonction de la cible de contrôle, je pense qu'il y a des cibles qui ne peuvent pas être contrôlées par PID. Nous devons repousser les limites de cette zone.

Résumé

・ J'ai essayé de jouer avec le contrôle PID ・ Les paramètres de contrôle ont été déterminés par la méthode de sensibilité limite de Ziegra Nichols. ・ J'ai essayé de reproduire le graphique affiché sur Wikipedia ・ J'ai pu définir explicitement une fonction qui décrit l'objet contrôlé. ・ Temps d'échantillonnage introduit dt

・ Je voudrais l'appliquer réellement au contrôle de la température et au contrôle du moteur.

Recommended Posts

[Introduction au PID] J'ai essayé de contrôler et de jouer ♬
[Introduction au modèle de maladie infectieuse] J'ai essayé de m'adapter et de jouer
J'ai implémenté DCGAN et essayé de générer des pommes
J'ai essayé de déboguer.
J'ai essayé de contrôler la bande passante et le délai du réseau avec la commande tc
[Introduction à AWS] J'ai essayé de porter une application de conversation et de jouer avec text2speech @ AWS ♪
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2 2
J'ai essayé pipenv et asdf pour le contrôle de version Python
J'ai essayé d'implémenter et d'apprendre DCGAN avec PyTorch
J'ai essayé d'ajouter un post-incrément à CPython. Présentation et résumé
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2
J'ai essayé d'ajouter des appels système et des planificateurs à Linux
[Introduction à Pytorch] J'ai essayé de catégoriser Cifar10 avec VGG16 ♬
J'ai essayé d'installer scrapy sur Anaconda et je n'ai pas pu
[Introduction à AWS] J'ai essayé de jouer avec la conversion voix-texte ♪
J'ai essayé d'apprendre PredNet
[J'ai essayé d'utiliser Pythonista 3] Introduction
J'ai essayé d'organiser SVM.
J'ai essayé d'implémenter PCANet
Introduction à l'optimisation non linéaire (I)
J'ai essayé de réintroduire Linux
J'ai essayé de présenter Pylint
J'ai essayé de résumer SparseMatrix
jupyter je l'ai touché
J'ai essayé d'implémenter StarGAN (1)
J'ai essayé de prédire et de soumettre les survivants du Titanic avec Kaggle
J'ai essayé de combiner Discord Bot et la reconnaissance faciale-pour LT-
J'ai essayé d'obtenir les informations du Web en utilisant "Requests" et "lxml"
[Introduction à la simulation] J'ai essayé de jouer en simulant une infection corona ♬
[Django] J'ai essayé d'implémenter des restrictions d'accès par héritage de classe.
[Introduction à Pandas] J'ai essayé d'augmenter les données d'échange par interpolation de données ♬
J'ai essayé d'illustrer le temps et le temps du langage C
J'ai essayé d'afficher l'heure et la météo d'aujourd'hui w
Mongodb Shortest Introduction (3) J'ai essayé d'accélérer même des millions
J'ai essayé d'énumérer les différences entre java et python
J'ai essayé de créer une interface graphique à trois yeux côte à côte avec Python et Tkinter
[Introduction à Mac] Applications et paramètres Mac pratiques que j'utilise
J'ai essayé d'implémenter Deep VQE
J'ai essayé de créer l'API Quip
J'ai essayé de toucher Python (installation)
[Introduction à Python3 Jour 1] Programmation et Python
J'ai essayé de mettre en place une validation contradictoire
J'ai essayé d'expliquer l'ensemble de données de Pytorch
J'ai touché l'API de Tesla
J'ai essayé de m'organiser à propos de MCMC.
J'ai essayé d'implémenter Realness GAN
J'ai essayé de déplacer le ballon
J'ai essayé d'estimer la section.
J'ai essayé de visualiser les signets volant vers Slack avec Doc2Vec et PCA
[Introduction à Python] J'ai comparé les conventions de nommage de C # et Python.
[Introduction à la simulation] J'ai essayé de jouer en simulant une infection corona ♬ Partie 2
J'ai essayé de laisser Pepper parler des informations sur l'événement et des informations sur les membres
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
J'ai essayé de créer des taureaux et des vaches avec un programme shell
J'ai essayé d'extraire des noms de joueurs et de compétences d'articles sportifs
J'ai essayé de créer un mécanisme de contrôle exclusif avec Go
J'ai essayé de créer un linebot (implémentation)
J'ai essayé de résumer la gestion des exceptions Python