Simulation d'un système par block¶
Le module BMS
, pour "Block Modeling Système", permet de simuler des systèmes dynamique représenté par un schéma-bloc.
Le système est décrit par une série de variables qui correspondent aux entrées et sorties des blocs. Ces variables sont liées par des équations ou des comportements.
Ce module permet de simuler certaines non-linéarités comme les saturations ou de type lois de Coulomb.
Attention
Le module semble ne plus fonctionner sur une version récente de Python ou Numpy.
Une alternative possible bdsim.
L'ensemble de la documentation est disponible ici.
Exemple de système dynamique, la machine à courant continu :
Installation¶
Pour installer le module BMS
voir installation d'un module.
Exemple d'utilisation¶
Simulation de la machine à courant continu présentée précédemment.
1 - Charger le module bms
¶
import bms
2 - Définition des entrées du système¶
Ici, nous avons 2 entrées : U(p) et C_p(p)
Le signal d'entrée est de type échelon pour les deux.
from bms.signals.functions import Step
U = Step('U', 1) # Echelon d'amplitude 1 appelé 'U'
Il existe 4 type de signal d'entrée :
Entrée | Fonction | Variables |
---|---|---|
Echelon | bms.signals.functions.Step(name='Step', amplitude=1, delay=0, offset=0) | name : Nom de l'entrée utilisée comme variable amplitude : amplitude de l'échelon delay : instant de l'échelon en seconde offset : valeur initiale |
Rampe | bms.signals.functions.Ramp(name='Ramp', amplitude=1, delay=0, offset=0) | name : Nom de l'entrée utilisée comme variable amplitude : pente de la rampe delay : instant du début de la rampe en seconde offset : valeur initiale |
Sinus | bms.signals.functions.Sinus(name='Sinus', amplitude=1, w=1, phase=0, offset=0) | name : Nom de l'entrée utilisée comme variable amplitude : pente de la rampe w : pulsation du sinus en rad/s phase : phase à l'origine en radian offset : valeur initiale |
Fonction | bms.signals.functions.SignalFunction(name, function) | name : Nom de l'entrée utilisée comme variable function : une fonction qui renvoie les valeurs temporelles du signal. |
Dans le cadre d'une simulation d'un véhicule roulant, il existe aussi une entrée qui représente un cycle "WLTP" :
bms.signals.wltp.WLTP1(name)
: signal d'un cycle WLTP de classe 1, la vitesse est en m/s ;bms.signals.wltp.WLTP2(name)
: signal d'un cycle WLTP de classe 2, la vitesse est en m/s ;bms.signals.wltp.WLTP2(name)
: signal d'un cycle WLTP de classe 3, la vitesse est en m/s.
Pour les classes voir Cycle WLTP.
3 - Définition des variables du systèmes¶
Les variables sont les grandeurs physiques qui évoluent au cours du temps dans le système.
# Nom court uniquement
epsilon = bms.Variable('epsilon', hidden=True)
I = bms.Variable('I')
Cem = bms.Variable('Cem', hidden=True)
deltaC = bms.Variable('deltaC', hidden=True)
Cr = bms.Variable('Cr')
# Nom long
Omega = bms.Variable(('Vitesse du moteur', 'Omega'))
E = bms.Variable(('Force électromotrice', 'E'), hidden=True)
Détail de la fonction bms.Variable(names='variable', initial_values=[0], hidden=False)
:
names
: nom de la variable, dans la cas d'un nom long (plusieurs mots) il faut fournir un tuple du type('Nom long','Nom court')
, le nom long sera celui afficher dans les graphiques, le nom court sera utilisé comme variable pour les calculs ;initial_values
: valeur initiale dans un tableau ;hidden
: cacher la variable lors du tracé des graphiques siTrue
.
4 - Définition des blocs¶
Cette partie permet de définir le comportement et les équations qui lient deux variables.
from bms.blocks.continuous import ODE, Gain, Subtraction
from bms.blocks.nonlinear import Saturation
from numpy import pi
comparateur_tension = Subtraction(U, E, epsilon)
R = 2.07 # Ohm
L = 0.227e-3 # H
bloc_electrique = ODE(epsilon, I, [1], [R, L])
Kt = 13.9e-3 # Nm/A
Ke = 1/(pi*689/30) # V.s/rad
couplage_couple = Gain(I, Cem, Kt)
couplage_electrique = Gain(Omega, E, Ke)
frottement = Saturation(Cem, Cr, -0.7923e-3, 0.7923e-3)
comparateur_couple = Subtraction(Cem, Cr, deltaC)
Jeq = 13.6e-7 # Kg.m²
dynamique = ODE(deltaC, Omega, [1], [0, Jeq])
Les blocs disponibles sont les suivants :
Bloc | Fonction | Comportement |
---|---|---|
Gain | bms.blocks.continuous.Gain(input_variable, output_variable, value, offset=0) | output_variable=value*input_variable+offset |
Sommateur | bms.blocks.continuous.Sum(inputs, output_variable) | output_variable=\sum inputs, les entrées sont décrites par un tableau '[entrée1,entrée2]' |
Comparateur | bms.blocks.continuous.Subtraction(input_variable1, input_variable2, output_variable) | output_variable=input_variable1-input_variable2 |
Multiplicateur | bms.blocks.continuous.Product(input_variable1, input_variable2, output_variable) | output_variable=input_variable1*input_variable2 |
Diviseur | bms.blocks.continuous.Division(input_variable1, input_variable2, output_variable) | output_variable=input_variable1/input_variable2 |
Fonction | bms.blocks.continuous.FunctionBlock(input_variable, output_variable, function) | output_variable=function(input_variable) |
Fonction de transfert | bms.blocks.continuous.ODE(input_variable, output_variable, a, b) | output_variable=input_variable*H(p) avec H(p)=\frac{a[i]p^i}{b[j]p^j} avec a et b les tableaux des coefficients de la fonction de transfert (poids faible en premier) |
Somme pondérée | bms.blocks.continuous.WeightedSum(inputs, output_variable, weights, offset=0) | output_variable=\sum([weights]*[inputs]+offset) où weights et inputs sont des tableaux de même longueur |
Les blocs de non-linéarité sont :
Bloc | Fonction | Comportement |
---|---|---|
Délai | bms.blocks.nonlinear.Delay(input_variable, output_variable, delay) | Applique un délai à l'entrée. |
Saturation | bms.blocks.nonlinear.Saturation(input_variable, output_variable, min_value, max_value) | L'entrée est saturée entre min_value et max_value. |
Force de Coulomb conditionner à la vitesse | bms.blocks.nonlinear.Coulomb(input_variable, speed_variable, output_variable, max_value, tolerance=0) | Retourne la force opposée dans l'intervalle de \pmtolerance, en dehors de l'intervalle cette force est saturée à max_value (principe du cône de frottement). |
Force de Coulomb, max piloté | bms.blocks.nonlinear.CoulombVariableValue(external_force, speed_variable, value_variable, output_variable, tolerance=0) | Similaire Coulomb , sauf que la condition max_value est pilotée par une variables. |
Signe | bms.blocks.nonlinear.Sign(input_variable, output_variable) | output = \begin{cases}-1, & \textrm{si } input\_variable < 0 \\0, & \textrm{si } nput\_variable = 0 \\1, & \textrm{si } input\_variable > 0\end{cases} |
5 - Définition du modèle¶
On définit ici les caractéristiques temporelles du modèle.
tf = 0.1 # Instant de fin de la simulation
ne = 100 # Nombre d'échantillons sur la durée tf
modele = bms.DynamicSystem(tf, ne, [comparateur_tension, bloc_electrique,
couplage_couple, couplage_electrique, frottement, comparateur_couple, dynamique])
6 - Simulation du modèle¶
modele.Simulate()
7 - Exploitation des résultats¶
Le module intègre plusieurs méthodes pour afficher les résultats :
- Afficher l'ensemble des variables sauf celles marquée
hidden
avec la fonction :système.PlotVariables()
- Afficher les variable sélectionnées à l'aide de la fonction :
système.PlotVariables([Variable1, Variable2])
. Il est possible d'afficher plusieurs graphiques différents en passant des tableaux dans le tableau de variables :système.PlotVariables([[Graphique1],[Graphique2]])
- Accéder indicvduellement à chacune des variables
# Méthode 1
# Affichage de toutes les variables non cachées
modele.PlotVariables()
# Méthode 2
# Affichage uniquement des variables sélectionnées
modele.PlotVariables([[I], [Omega], [deltaC, Cem, Cr]])
# Méthode 3
# Accès individuel aux variables
import matplotlib.pyplot as plt
plt.plot(modele.t, I.values, label="Courant moteur (A)")
plt.plot(modele.t, Cem.values*100, label="Couple moteur (Nm*100)")
plt.grid()
plt.title("Courant et couple moteur")
plt.xlabel("Temps (s)")
plt.ylabel("Amplitude")
plt.legend()
plt.show()
Exemple complet¶
from numpy import pi
from bms.blocks.nonlinear import Saturation
from bms.blocks.continuous import ODE, Gain, Subtraction
import bms
from bms.signals.functions import Step
# 1 - Définition de ou des entrées
U = Step('U', 1) # Echelon d'amplitude 1 appelé 'U'
# 2 - Définition des variables
# Nom court uniquement
epsilon = bms.Variable('epsilon', hidden=True)
I = bms.Variable('I')
Cem = bms.Variable('Cem', hidden=True)
deltaC = bms.Variable('deltaC', hidden=True)
Cr = bms.Variable('Cr')
# Nom long
Omega = bms.Variable(('Vitesse du moteur', 'Omega'))
E = bms.Variable(('Force électromotrice', 'E'), hidden=True)
# 3 - Définition des blocs
comparateur_tension = Subtraction(U, E, epsilon)
R = 2.07 # Ohm
L = 0.227e-3 # H
bloc_electrique = ODE(epsilon, I, [1], [R, L])
Kt = 13.9e-3 # Nm/A
Ke = 1/(pi*689/30) # V.s/rad
couplage_couple = Gain(I, Cem, Kt)
couplage_electrique = Gain(Omega, E, Ke)
frottement = Saturation(Cem, Cr, -0.7923e-3, 0.7923e-3)
comparateur_couple = Subtraction(Cem, Cr, deltaC)
Jeq = 13.6e-7 # Kg.m²
dynamique = ODE(deltaC, Omega, [1], [0, Jeq])
# 4 - Définition du modèle de simulation
tf = 0.1 # Instant de fin de la simulation
ne = 100 # Nombre d'échantillons sur la durée tf
modele = bms.DynamicSystem(tf, ne, [comparateur_tension, bloc_electrique,
couplage_couple, couplage_electrique, frottement, comparateur_couple, dynamique])
# 5 - Simulation
modele.Simulate()
# 6 - Affichage uniquement des variables sélectionnées
modele.PlotVariables([[I], [Omega], [deltaC, Cem, Cr]])