I. Introduction▲
Les process industriels impliquent souvent des calculs complexes et nécessitent donc un peu d'expérience pour appréhender le code mis en œuvre. Le but n'étant pas d'alourdir le propos avec des formules trop compliquées, je vais donc essayer de décrire un exemple simple de simulation d'un process industriel dans Ms Access, suivant une gamme de fabrication.
II. Contexte▲
Dans l'industrie, les machines peuvent être regroupées en ensembles autonomes de production spécialisés par type de produits qui utilisent les mêmes machines : ces ensembles s'appellent des îlots. Les flux de produits (matières) peuvent utiliser les postes de travail de l'îlot dans un ordre différent suivant leur gamme de fabrication, alors que dans une ligne de fabrication l'ordre est impératif.
Pour simplifier, on va ici considérer une gamme de fabrication composée de m machines placées en série et négliger les durées de transfert entre machines.
III. Description du principe▲
L'objectif est d'obtenir, à partir de formules mathématiques, le nombre de pièces en attente sur une machine quelconque ainsi que le total des pièces déjà usinées à un instant donné. Nous injecterons ces fonctions traduites en VBA dans des requêtes pour afficher et représenter la progression des pièces sur les différentes machines.
III-A. Formules mathématiques de base mises en œuvre▲
duree_fabrication =
(
n-
1
)*
duree_max +
duree_total
- duree_max : durée de passage la plus longue entre les machines.
- duree_total : durée totale de passage sur les machines.
On en déduit :
nbre_fabrique =
((
d -
duree_total) \
duree_max) +
1
C'est cette formule mathématique qui va nous servir de base pour nos calculs dans nos requêtes.
III-B. Formules mathématiques généralisées▲
duree_passage
(
i) =
(
n-
1
)*
duree_max
(
i) +
duree_total
(
i)
- duree_max(i) : durée de passage la plus longue entre les machines d'indice 1 à i.
- duree_total(i) : durée totale de passage sur les i machines.
En inversant la formule on obtient :
nbre_passe
(
i) =
((
d -
duree_total
(
i)) \
duree_max
(
i)) +
1
Nous utilisons ici la division entière, notée « \ » en VBA, pour obtenir un nombre entier de pièces.
On en déduit enfin :
nbre_attente
(
i) =
(((
d -
duree_total
(
i-
1
)) \
duree_max
(
i-
1
)) +
1
) -
(((
d -
duree_total
(
i)) \
duree_max
(
i)) +
1
)
- duree_max(i-1) : durée de passage la plus longue entre les machines d'indice 1 à (i-1) ;
- duree_total(i-1) : durée totale de passage sur l'ensemble des (i-1) machines ;
- duree_max(i) : durée de passage la plus longue entre les machines d'indice 1 à i ;
- duree_total(i) : durée totale de passage sur les i machines.
Cette dernière formule va nous permettre de connaître, à un instant donné, le nombre de pièces en attente sur une machine quelconque et surtout, le nombre total de pièces déjà terminées en bout de gamme.
IV. Rendu final de la simulation du process▲
Voici le rendu du formulaire qui présente, pour chaque machine, le nombre de pièces en attente et donc la progression des pièces usinées.
On constate que le programme permet de visualiser, pour chaque tranche horaire, le plan de charge de toutes les machines.
Voici les objets nécessaires pour aboutir à ce résultat.
V. Les tables nécessaires▲
Pour sauvegarder les durées d'usinage sur chaque machine ainsi que les jours et tranches horaires intervenant dans la simulation, nous aurons besoin de trois tables :
V-A. La table T_Creneau▲
Cette table contient la liste des créneaux horaires accompagnés de leur indice.
Nom du champ |
Type de données |
Description |
---|---|---|
Indice |
Numérique |
Indice du créneau horaire |
Creneau |
Texte |
Créneau horaire |
V-B. La table T_Jour ▲
Elle permet d'enregistrer les indices des jours durant lesquels se déroule le processus industriel.
Nom du champ |
Type de données |
Description |
---|---|---|
Jour |
Entier long |
Numéro d'ordre du jour |
V-C. La table T_Machine▲
Cette table permet de sauvegarder les noms des machines et les durées de passage des pièces qui peuvent être paramétrés.
Nom du champ |
Type de données |
Description |
---|---|---|
Indice |
Entier long |
Numéro d'ordre de la machine |
Machine |
Texte |
Nom de la machine |
Duree |
Entier long |
Durée de passage sur la machine |
VI. Les requêtes pour la partie simulation▲
Afin de pouvoir afficher, pour chaque jour et chaque tranche horaire, le plan de charge simulé des machines, on a besoin de réaliser quelques requêtes.
VI-A. La requête affichant les tranches horaires▲
Cette requête paramétrée réalise le produit cartésien entre la table T_Creneau et T_Jour, pour afficher toutes les tranches horaires du process :
On constate que la requête comprend, dans la partie encerclée, des champs calculés que nous allons détailler.
VI-A-1. La formule donnant les jours▲
DateJour
:
AjDate
(
"j"
;[Jour]-
1
;ValDate
(
[Forms]![F_Simuler_Process]![Date_Debut]))
- [Forms]![F_Simuler_Process]![Date_Debut] : paramètre donnant la date et l'heure du début du process.
VI-A-2. La formule donnant les heures▲
Horaire
:
AjDate
(
"n"
;(
[Indice]-
1
)*
Forms!F_Simuler_Process!Creneau;Forms!F_Simuler_Process!Horaire_Debut)
- [Forms]![F_Simuler_Process]![Creneau] : paramètre donnant la durée des tranches horaires.
- [Forms]![F_Simuler_Process]![Horaire_Debut] : paramètre donnant l'heure du début du process.
VI-A-3. La formule donnant les dates et heures▲
Les dates et horaires pris en compte dans la simulation s'obtiennent en fonction du paramètre définissant le 1er jour et le 1er horaire :
DateHeure
:
CDate
(
AjDate
(
"j"
;[Jour]-
1
;ValDate
(
[Forms]![F_Simuler_Process]![Date_Debut])) &
" "
&
AjDate
(
"n"
;(
[Indice]-
1
)*
[Forms]![F_Simuler_Process]![Creneau];[Forms]![F_Simuler_Process]![Horaire_Debut]))
VI-A-4. Fonction évaluant la date et l'heure de fin du process▲
On évalue la date et l'heure de fin du processus à partir de la formule de base définie précédemment :
duree_fabrication =
(
n-
1
)*
duree_max +
duree_total
La fonction VBA mise en œuvre pour ce calcul va permettre de filtrer la requête sur le champ date et heure :
Public
Function
fin_process
(
ByVal
nbre As
Long
, ByVal
debut As
Date
, ByVal
Horaire_Debut, ByVal
Horaire_Fin, ByVal
Creneau As
Integer
) As
Date
' date et heure de fin du process en fonction du nombre de pièces, de la date de début du process,
' des heures de début et de fin dans la journée et du créneau horaire.
Dim
rs As
DAO.Recordset
Dim
leSql As
String
Dim
d As
Long
, d1 As
Long
, d2 As
Long
Dim
dt As
Date
Dim
j As
Integer
Dim
m As
Long
' requête affichant la durée totale du process en se basant sur la formule (n-1)*duree_max + duree_total.
leSql =
"SELECT "
&
(
nbre -
1
) &
"*Max([Duree])+Sum([Duree]) AS durée "
&
_
"FROM T_Machine;"
' le jeu d'enregistrement correspondant.
Set
rs =
CurrentDb.OpenRecordset
(
leSql, dbOpenForwardOnly)
' la durée totale.
d =
rs!durée
rs.Close
Set
rs =
Nothing
d1 =
DateDiff
(
"s"
, TimeValue
(
debut), Horaire_Fin)
If
d <=
d1 Then
' si compris dans l'intervalle.
fin_process =
DateAdd
(
"s"
, d, debut)
Else
' sinon on décompose la durée.
d =
d -
d1
dt =
CDate
(
Format
(
debut +
1
, "dd/mm/yyyy"
) &
" "
&
Format
(
Horaire_Debut, "hh:nn"
))
m =
DateDiff
(
"s"
, Horaire_Debut, Horaire_Fin)
j =
d \
m
dt =
DateAdd
(
"d"
, j, dt)
dt =
DateAdd
(
"s"
, d Mod
m, dt)
fin_process =
dt
End
If
' renvoie la date et l'heure de fin du process.
fin_process =
DateAdd
(
"s"
, (
Creneau *
60
), fin_process)
End
Function
VI-B. La requête affichant la charge des machines▲
Cette requête paramétrée réalise le produit cartésien entre la requête précédente R_Horaire2 et la table T_Machine, de manière à afficher toutes les tranches horaires du process et les quantités en attente sur chaque machine :
On remarque que la requête comprend dans la partie encerclée des champs calculés que nous allons détailler.
VI-B-1. Mise en œuvre de la formule généralisée▲
Nous avons en fait injecté dans la requête au niveau du champ Nbre la formule généralisée vue précédemment :
nbre_attente
(
i) =
(((
d -
duree_total
(
i-
1
)) \
duree_max
(
i-
1
)) +
1
) -
(((
d -
duree_total
(
i)) \
duree_max
(
i)) +
1
)
À cet effet, nous avons évalué les différentes durées maximales et totales au moyen de fonctions de domaine.
VI-B-1-a. Durée totale (i-1)▲
Duree_Total1
:
SomDom
(
"Duree"
;"T_Machine"
;"Indice<="
&
(
[T_Machine_1].
[Indice]-
1
) &
" or ( Indice=1)"
)
On choisit ici une fonction de domaine, dans la seconde version de l'exemple disponible en téléchargement nous utilisons une sous-requête à la place.
VI-B-1-b. Durée maximum (i-1)▲
Duree_Max1
:
MaxDom
(
"Duree"
;"T_Machine"
;"Indice<="
&
(
[T_Machine_1].
[Indice]-
1
) &
" or ( Indice=1)"
)
VI-B-1-c. Durée totale (i)▲
Duree_Total2
:
SomDom
(
"[Duree]"
;"T_Machine"
;"Indice<="
&
[T_Machine_1].
[Indice])
VI-B-1-d. Durée maximum (i)▲
Duree_Max2: MaxDom
(
"Duree"
;"T_Machine"
;"Indice<="
&
[T_Machine_1].
[Indice])
Puis, on a inséré dans le champ nbre de la requête principale une fonction VBA qui est la traduction de la formule généralisée mentionnée plus haut.
VI-B-1-e. Nombre de pièces en attente à l'indice i▲
On a injecté la formule généralisée vue précédemment au niveau de la requête en utilisant une fonction VBA fnc_nbre :
Nbre
:
VraiFaux
(
T_Machine_1.Indice
=
12
;fnc_Nbre
(
Forms!F_Simuler_Process!Date_Debut;[DateHeure];Forms!F_Simuler_Process!Horaire_Debut;Forms!F_Simuler_Process!Horaire_Fin;[Duree_Total2];[Duree_Max2];Forms!F_Simuler_Process!Nbre_Pieces);(
VraiFaux
(
T_Machine_1.Indice
=
1
;Forms!F_Simuler_Process!Nbre_Pieces;fnc_Nbre
(
Forms!F_Simuler_Process!Date_Debut;[DateHeure];Forms!F_Simuler_Process!Horaire_Debut;Forms!F_Simuler_Process!Horaire_Fin;[Duree_Total1];[Duree_Max1];Forms!F_Simuler_Process!Nbre_Pieces)))-
fnc_Nbre
(
Forms!F_Simuler_Process!Date_Debut;[DateHeure];Forms!F_Simuler_Process!Horaire_Debut;Forms!F_Simuler_Process!Horaire_Fin;[Duree_Total2];[Duree_Max2];Forms!F_Simuler_Process!Nbre_Pieces))
On utilise ici la fonction VraiFaux pour tester si on est en bout de gamme (l'indice égal à 12 est juste un indicateur de fin supérieur au nombre maximum de machines), dans ce cas, on calcule le nombre de pièces fabriquées. L'expression comprend également la fonction fnc_Nbre qui donne le nombre de pièces passées sur les i machines, après une durée d.
Les champs durées et date/heure définis précédemment :
- Duree_Max1 : durée maximum jusqu'à la machine d'indice (i-1) ;
- Duree_Total1 : durée totale jusqu'à la machine d'indice (i-1) ;
- Duree_Max2: durée maximum jusqu'à la machine d'indice (i) ;
- Duree_Total2 : durée totale jusqu'à la machine d'indice (i) ;
- DateHeure : date et heure prises en compte pour le calcul.
Les paramètres de la simulation (début et fin du process) qui sont des zones de texte situées sur le formulaire simulateur du process :
- Forms!F_Simuler_Process!Date_Debut : paramètre indiquant la date et l'heure de début de la simulation ;
- Forms!F_Simuler_Process!Horaire_Debut : paramètre indiquant l'heure de début du process ;
- Forms!F_Simuler_Process!Horaire_Fin : paramètre indiquant l'heure de fin du process.
Public
Function
fnc_Nbre
(
ByVal
debut As
Date
, ByVal
fin As
Date
, ByVal
Horaire_Debut As
Date
, ByVal
Horaire_Fin As
Date
, ByVal
duree_total As
Integer
, ByVal
duree_max As
Integer
, ByVal
nbre As
Long
) As
Long
' nombre de pièces passées sur la machine en fonction de la durée totale et de la durée max. jusqu'à cette machine.
Dim
j As
Integer
Dim
d1 As
Long
, d2 As
Long
Dim
d As
Long
j =
DateDiff
(
"d"
, debut, fin)
If
j >
1
Then
' process sur plusieurs jours.
d =
(
j -
1
) *
DateDiff
(
"s"
, Horaire_Debut, Horaire_Fin)
d1 =
DateDiff
(
"s"
, TimeValue
(
debut), Horaire_Fin)
d2 =
DateDiff
(
"s"
, Horaire_Debut, TimeValue
(
fin))
d =
d +
d1 +
d2
ElseIf
(
j =
1
) Then
' simulation sur 1 jour entier.
d1 =
DateDiff
(
"s"
, TimeValue
(
debut), Horaire_Fin)
d2 =
DateDiff
(
"s"
, Horaire_Debut, TimeValue
(
fin))
d =
d1 +
d2
Else
' process se déroulant dans la journée.
d =
DateDiff
(
"s"
, TimeValue
(
debut), TimeValue
(
fin))
End
If
If
(
d >=
duree_total) Then
fnc_Nbre =
(
d -
duree_total) \
duree_max +
1
' formule mathématique définie dans l'article.
If
fnc_Nbre >
nbre Then
fnc_Nbre =
nbre
End
If
Else
fnc_Nbre =
0
End
If
End
Function
VI-B-1-f. Date et heure de fin du process▲
On évalue la date et l'heure de fin du processus à partir de la formule de base définie précédemment :
duree_fabrication =
(
n-
1
)*
duree_max +
duree_total
La fonction VBA mise en œuvre pour ce calcul est la suivante :
Public
Function
fin_process
(
ByVal
nbre As
Long
, ByVal
debut As
Date
, ByVal
Horaire_Debut, ByVal
Horaire_Fin, ByVal
Creneau As
Integer
) As
Date
' date et heure de fin du process en fonction du nombre de pièces, de la date de début du process,
' des heures de début et de fin dans la journée et du créneau horaire.
Dim
rs As
DAO.Recordset
Dim
leSql As
String
Dim
d As
Long
, d1 As
Long
, d2 As
Long
Dim
dt As
Date
Dim
j As
Integer
Dim
m As
Long
' requête affichant la durée totale du process en se basant sur la formule (n-1)*duree_max + duree_total.
leSql =
"SELECT "
&
(
nbre -
1
) &
"*Max([Duree])+Sum([Duree]) AS durée "
&
_
"FROM T_Machine;"
' le jeu d'enregistrement correspondant.
Set
rs =
CurrentDb.OpenRecordset
(
leSql, dbOpenForwardOnly)
' la durée totale.
d =
rs!durée
rs.Close
Set
rs =
Nothing
d1 =
DateDiff
(
"s"
, TimeValue
(
debut), Horaire_Fin)
If
d <=
d1 Then
' si compris dans l'intervalle.
fin_process =
DateAdd
(
"s"
, d, debut)
Else
' sinon on décompose la durée.
d =
d -
d1
dt =
CDate
(
Format
(
debut +
1
, "dd/mm/yyyy"
) &
" "
&
Format
(
Horaire_Debut, "hh:nn"
))
m =
DateDiff
(
"s"
, Horaire_Debut, Horaire_Fin)
j =
d \
m
dt =
DateAdd
(
"d"
, j, dt)
dt =
DateAdd
(
"s"
, d Mod
m, dt)
fin_process =
dt
End
If
' renvoie la date et l'heure de fin du process.
fin_process =
DateAdd
(
"s"
, (
Creneau *
60
), fin_process)
End
Function
VII. Le formulaire de simulation▲
Nous allons décrire le formulaire qui présente la simulation du process sur les différentes machines de la gamme de fabrication.
Le programme permet de visualiser pour chaque tranche horaire le plan de charge de toutes les machines.
VII-A. La zone de liste affichant les horaires▲
Sur la partie gauche du formulaire se trouve une zone de liste qui affiche l'ensemble des tranches horaires prises en compte dans la simulation du process. Elles sont sous la forme Jour/Heure.
VII-B. Le graphique pour afficher la charge des machines▲
Sur la plus grande partie du formulaire se trouve le graphique qui affiche le plan de charge des machines dont voici le SQL :
PARAMETERS
[Forms]
![F_Simuler_Process]
![Nbre_Pieces]
Value
;
TRANSFORM First
(
R_Horaire_Machine_Piece.Nbre)
AS
First_Nbre
SELECT
R_Horaire_Machine_Piece.Machine FROM
R_Horaire_Machine_Piece
GROUP
BY
R_Horaire_Machine_Piece.Machine
PIVOT R_Horaire_Machine_Piece.Machine In
(
"M1"
,"M2"
,"M3"
,"M4"
,"M5"
,"M6"
,"Total fait"
)
;
VIII. Téléchargement▲
Pour faciliter les tests et assurer sa portabilité, la base exemple n'utilisera pas de composants externes à Access (ActiveX ou autres).
La base exemplesimuler_process est au format Access 2000.
IX. Remerciements▲
Un grand Merci à toute l'équipe de Dvp et plus particulièrement à :
Pour ses remarques et conseils avisés :
. claudeleloup
Pour leur relecture :
. claudeleloup
. franouch
. Oppenheimer