Aller au contenu

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 :

Schéma-bloc de 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 si True.

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)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).
Loi de Coulomb
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 hiddenavec 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()

png

# Méthode 2
# Affichage uniquement des variables sélectionnées
modele.PlotVariables([[I], [Omega], [deltaC, Cem, Cr]])

png

# 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()

png

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]])

png