![]()
Le code ci-dessous permet de simuler la trajectoire d'une voiture sur une voie ayant le profil ci-dessus, entièrement dans un plan vertical. A tout instant, la position de la voiture est déterminée par :Lorsque la voiture atteint la limite gauche (X(t) = -1.2), elle ne va pas plus loin et sa vitesse est remise à 0. La vitesse est limitée à 0.07, dans les deux sens. Lorsque la voiture sort du secteur par la droite (X(t) > 0.5), la simulation est arrêtée. On mesure le temps que met la voiture pour atteindre ce but.
- une fonction X(t+1) = f(X(t), V(t+1)),
- une fonction V(t+1) = f(V(t), X(t), U(t)), où U(t) est une action de contrôle (1 ou -1 selon que le pilote de la voiture accélère ou freine pendant l'intervalle de temps ]t, t+1]). Cette action de contrôle est déterminée par une stratégie U(t) = f(V(t), X(t)). La vitesse est positive quand la voiture va de gauche à droite, et négative en sens contraire,
- la position initiale X(0) dans [-1.2, 0.5] et la vitesse initiale V(0) dans [-0.07, 0.07].
Fichier : UserEntity.cc
#include "UserEntity.h" Voiture::Voiture() { SetMetaClass(VOITURE); //SetParentClassId(O_ENTITY); // pour mémoire AddInstanceToClass(); AddComponentClassId (CONDUCTEUR); Descriptor* pD; pD = new InitialPosition(); AddConstantDescriptor (pD); pD = new InitialSpeed(); AddConstantDescriptor (pD); pD = new Speed(); AddVariableDescriptor (pD); pD = new State(); AddVariableDescriptor (pD); pD = new Position(); AddVariableDescriptor (pD); SpeedMonitor->AttachToDescriptor(this, SPEED); }; Conducteur::Conducteur() { SetMetaClass(CONDUCTEUR); //SetParentclassId(O_ENTITY); // pour mémoire AddInstanceToClass(); Descriptor* pD; pD = new Command(); AddVariableDescriptor (pD); };
Constructeur d'instances de voitures. Attachement de la métaclasse adéquate, celle dont le symbole est celui de la classe. La hiérarchie est définie sur la métaclasse. Une voiture a un composant de type conducteur. Construction et attribution des descripteurs variables (position et vitesse). Construction et attribution des descripteurs constants (position et vitesse initiale). La variable State sera mise à 0 dès que le but sera atteint (cf. UserContinuousProcess.cc). Attachement d'un démon à la variable vitesse. Constructeur d'instances de pilotes. Construction et attribution d'un descripteur variables (l'action de commande).
Fichier : UserTypes.h
enum App_ClassId {CONDUCTEUR = 201, VOITURE}; enum App_DescriptorId {COMMAND = 201, INITIAL_POSITION, INITIAL_SPEED, POSITION, SPEED, STATE}; enum ProcessId {COURSE = 1, SET_COMMAND};
Déclaration des symboles de classe utilisés dans le programme.
Fichier : UserConstantDescriptor.cc
#include "UserConstantDescriptor.h" #include "UserTypes.h" InitialPosition::InitialPosition() { ClassName ("initialPosition"); ClassSymbol (INITIAL_POSITION); SetDefaultValue (-1.2); }; InitialSpeed::InitialSpeed() { ClassName ("initialSpeed"); ClassSymbol (INITIAL_SPEED); SetDefaultValue (0.); };
Constructeurs des classes de descripteurs constants.
Fichier : UserVariableDescriptor.cc
#include "UserVariableDescriptor.h" #include "UserTypes.h" Position::Position() { ClassName ("position"); ClassSymbol (POSITION); SetDefaultValue (-1.2); PosDomain* p = new PosDomain(); SetDomain(p); }; Speed::Speed() { ClassName ("speed"); ClassSymbol (SPEED); SetDefaultValue (0.); }; State::State() { ClassName ("state"); ClassSymbol (STATE); SetDefaultValue (1); }; Command::Command() { ClassName ("command"); ClassSymbol (COMMAND); SetDefaultValue (0); };
Constructeurs des classes de descripteurs variables. Affectation d'un domaine de valeurs.
Fichier : UserDescValueSpec.cc
#include "UserDescValueSpec.h" #include "UserTypes.h" PosDomain::PosDomain() : DescFloatValueSpec(IN){ ClassName("posDomain"); AddSubDomain(-1.3, 0.55); SortOnLowBound(); ReduceToDisjunction(); };
Constructeur d'une classe de domaines de valeur. On ne créera qu'une instance, pour le descripteur Position.
Fichier : UserFunction.cc
#include "UserFunction.h" void InitSimulation() { pCurrentSim = new Simulation(); //... App_AssignInstantiators(); D_InstallMetaClasses(); App_InstallMetaClasses(); SetHierarchy(); D_DefineMonitors(); App_DefineMonitors(); } void App_InstallMetaClasses() { App_MakeClassIdToCharTab(); App_MakeDescIdToCharTab(); MetaClass* pMC; pMC = CreateMetaClass(CONDUCTEUR, "conducteur"); pMC->SetParentClassId(O_ENTITY); pMC = CreateMetaClass(VOITURE, "voiture"); pMC->SetParentClassId(O_ENTITY); } void App_AssignInstantiators() { Assign_App_NewEntityFromStringFunction( App_NewEntityFromString); Assign_App_NewProcessFromStringFunction( App_NewProcessFromString); Assign_App_NewEventFromStringFunction( App_NewEventFromString); Assign_App_NewEntitySpecFromStringFunction( App_NewEntitySpecFromString); ///... }; Entity* App_NewEntityFromString(char* nom) { if (!strcmp(nom, "conducteur")) return new Conducteur(); if (!strcmp(nom, "voiture")) return new Voiture(); return NULL; }; Process* App_NewProcessFromString(char* nom) { if (!strcmp(nom, "course")) return new Course(); if (!strcmp(nom, "setCommand")) return new SetCommand(); return NULL; } Event* App_NewEventFromString(char* nom) { if (!strcmp(nom, "eventCommand")) return new EventCommand(); return NULL; }
Fonction d'initialisation de la simulation: création de l'intance de Simulation ; assignation des fonctions d'instanciation ; installation des métaclasses BASIC DIESE ; installation des métaclasses de l'application ; établissement des liens hiérarchiques ; installation des moniteurs de BASIC DIESE ; installation des moniteurs de l'application ; Réalisation d'une fonction déclarée dans DIESE : initialisation des informations sur les sous-classes d'entités. Informations encapsulées dans des métaclasses. Déclaration du lien hiérarchique. Réalisation d'une fonction déclarée dans DIESE : déclaration des fonctions d'instanciation d'objets à partir de leur nom ou symbole de classe. Fonction d'instanciation des entités à partir ... ... du nom de classe. Fonction d'instanciation des processus à partir ... ... du nom de classe. Fonction d'instanciation des événements à partir ... ... du nom de classe.
Fichier : UserFunction.cc (suite)
void App_ParseMainArguments (int argc, char* argv[]) { if(argc < 6) { printf("Usage : main system_parameters simulation_parameters output_specifications structure directives"); printf(" [-m(emory)] [-v(erbose)] [-T] \n"); exit(0); }; for (int i=6;i < argc;i++) { if(!strcmp(argv[i],"-v")) gTraceActionMode=TRACE_ACTION_ON; if(!strcmp(argv[i],"-m")) gTraceNewDelMode=TRACE_NEWDEL_ON; if(!strcmp(argv[i],"-T")) gTraceTableauMode=TRACE_TABLEAU_ON; }; };
Fonction d'interprétation de la ligne de commande.
Fichier : UserMonitor.h
#include "UserTypes.h" extern DescValueMonitor* SpeedMonitor;
Déclaration d'un démon.
Fichier : UserMonitor.cc
#include "UserMonitor.h" DescValueMonitor* SpeedMonitor; float speed_whenSetFloat_Body(MonitorMethod* pM) { Descriptor* pVD = pM->GetDescriptorArgValue(MONITOREDDESCRIPTOR_ARGUMENT); float oldValue = pM->GetFloatArgValue(CURRENTFLOATVALUE_ARGUMENT); float newValue = pM->GetFloatArgValue(CANDIDATEFLOATVALUE_ARGUMENT); if (((oldValue>0) && (newValue<=0)) || ((oldValue<0) && (newValue>=0))) { Entity* pCar = pVD->DescribedEntity(); Entity* pDriver = pCar->GetComponent(CONDUCTEUR); printf("\nChangement de direction en X = %5.3f (U = %d) date : %d", pCar->GetFloatValue(POSITION), pDriver->GetIntValue(COMMAND), pCurrentSim->Clock()); }; return newValue; }; void App_DefineMonitors() { SpeedMonitor = new DescValueMonitor("speedMonitor"); SpeedMonitor->AssignWhenSetFloatMethod(speed_whenSetFloat_Body); };
Réservation d'un emplacement mémoire pour le démon. Définition de la fonction qui sera déclenchée lors de chaque modification de la vitesse de la voiture (simple affichage). La nouvelle valeur est retournée pour être affectée à la voiture. Définition de la fonction de création du démon avec attachement de la fonction ci-dessus.
Fichier : UserEvent.cc
#include "UserEvent.h" bool eventCommand_generateNextEvent_Body(EventMethod* pM) { Event* pCurrentEvent = pM->DescribedEvent(); Process* pCurrentProcess = pCurrentEvent->FirstProcess(); Entity* pCar = (pCurrentProcess->ProcessedEntity())->GetSuperEntity(); if (pCar->GetIntVarValue(STATE) == 1) { Event* pNewEvent = pCurrentEvent->RawCopy(); pNewEvent->SetOccurrenceClockTime(pCurrentSim->Clock()+1); pCurrentEvent->SetNextEvent(pNewEvent); return true; } else return false; }; EventCommand::EventCommand() { ClassName("eventCommand"); ClearListProcessAction (); HasPostConsequence(FALSE); IsAutoGenerate(TRUE); SetGenerateNextEvent(eventCommand_generateNextEvent_Body); };
Définition de l'événement de détermination de la commande. Un tel événement doit intervenir à chaque pas de temps. Sa seule conséquence sera de provoquer le processus de détermination de la commande. Définition de la fonction de génération d'un nouvel événement du même type, avec le même processus en jeu. La génération n'est faite que si le processus de déplacement de la voiture ne doit pas être interrompu (State = 1). L'événement est programmé pour dans 1 pas de temps. Constructeur de l'événement. Affectation de la fonction d'autogénération définie ci-dessus.
Fichier : UserDiscreteProcess.cc
#include "UserDiscreteProcess.h" void setCommand_execProcess_Body(ProcessMethod* pM) { DiscreteProcess* pP = pM->DescribedDiscreteProcess(); Entity* pDriver = (Entity*)(pP->ProcessedEntity()); Entity* pCar = (Entity*)(pDriver->GetSuperEntity()); float X = pCar->GetFloatVarValue(POSITION); float V = pCar->GetFloatVarValue(SPEED); float frontiere = - 0.06*pow(X, 2) - 0.03*X + 0.01; if (V < frontiere) pDriver->SetIntVarValue(COMMAND, -1); else pDriver->SetIntVarValue(COMMAND, +1); }; SetCommand::SetCommand() : DiscreteProcess(SET_COMMAND, "setCommand") { SetExec(setCommand_execProcess_Body); };
Définition de la fonction de détermination de la commande U(t) : on définit une frontière dans le domaine X x V, en dessous de laquelle on freine et au dessus de laquelle on accélère. L'entité sur lequel porte le processus (renvoyé par le message ProcessedEntity()) est déter- miné dans main.cc, par le message ProcessedEntity(Entity*). Constructeur des instances de processus de dé- termination de U(t), auxquelles on attache la fonction ci-dessus. Un tel processus sera crée et exécuté à chaque pas de temps.
Fichier : UserContinuousProcess.cc
#include "UserContinuousProcess.h" void course_initializeProcess_Body(ProcessMethod* pM) { ContinuousProcess* pP = pM->DescribedContinuousProcess(); DescriptedEntity* pDO = pP->ProcessedEntity(); pDO->SetFloatVarValue(POSITION, pDO->GetFloatConstValue(INITIAL_POSITION)); pDO->SetFloatVarValue(SPEED, pDO->GetFloatConstValue(INITIAL_SPEED)); }; void course_stopProcess_Body(ProcessMethod* pM) { ContinuousProcess* pP = pM->DescribedContinuousProcess(); ((ContinuousProcess*)pP)->ToBeStopped(TRUE); DescriptedEntity* pCar = pP->ProcessedEntity(); printf("\n\n ==> Position finale : X = %5.3f, vitesse = %5.3f\n", pCar->GetFloatValue(POSITION),pCar->GetFloatValue(SPEED)); printf(" temps simulé = %d", pCurrentSim->Clock()); }; void course_goOneStepForwardProcess_Body(ProcessMethod* pM) { ContinuousProcess* pP = pM->DescribedContinuousProcess(); DescriptedEntity* pCar = pP->ProcessedEntity(); Entity* pDriver = (Entity*)(pCar->GetComponent(CONDUCTEUR)); float Xt = pCar->GetFloatVarValue(POSITION); float Vt = pCar->GetFloatVarValue(SPEED); int Ut = pDriver->GetIntVarValue(COMMAND); float Vtp1 = Vt+0.001*Ut-0.0025*cos(3*Xt); float Xtp1 = Xt+Vtp1; if (Xtp1 > 0.5) { pCar->SetFloatVarValue(POSITION, Xtp1); pCar->SetFloatVarValue(SPEED, Vtp1); pCar->SetIntVarValue(STATE, 0); pP->ExecVoidMethod(STOP_PROCESS); } else if (Xtp1 < -1.2) { Xtp1 = -1.2; Vtp1 = 0.0; }; if (Vtp1 > 0.07) { Vtp1 = 0.07; } else if (Vtp1 < -0.07) { Vtp1 = -0.07; }; pCar->SetFloatVarValue(POSITION, Xtp1); pCar->SetFloatVarValue(SPEED, Vtp1); }; Course::Course() : ContinuousProcess(COURSE, "course") { Pas(1); SetInitialize(course_initializeProcess_Body); SetGoOneStepForward(course_goOneStepForwardProcess_Body); SetStop(course_stopProcess_Body); };
Définition de la fonction d'initialisation de la trajectoire. Les variables position et vitesse prennent la valeur des paramètres position initiale et vitesse initiale. Définition de la fonction d'arrêt du dé- placement de la voiture. La méthode ToBeStopped fait partie de la bibliothèque DIESE. Définition de la fonction de changement d'état de la voiture pour un pas de temps. Calcul de la nouvelle vitesse V(t+1) et de la nouvelle position X(t+1). Si le but est atteint, la variable State est mise à 0, et le processus est arrêté. Si la limite gauche est atteinte, la vitesse est mise à 0. Sinon, elle est éventuellement limitée à 0.07. Les valeurs terminales sont attribuées aux descripteurs Position et Vitesse de la voiture. Constructeur d'instances du processus de dé- placement d'une voiture. Affectation des fonctions précédemment définies.
Fichier paramètres du système: sim0.par
// parametres du système toboggan ENTITE voiture position_initiale <- -0.5; ENTITE voiture vitesse_initiale <- 0.0;
Déclaration de deux paramètres à valeur flottante.
Fichier des paramètres de la simulation : sim0.sim
INITIALISATION SIMULATION UNITE_TPS SECOND; NB_UNITE_TPS 1; DATE_DEBUT 1 JAN 2000 12 0 0; DATE_FIN 1 JAN 2000 12 4 0; OUT_DIR "/home/durand/DIESE/KBS/bdiese/Toboggan/out/"; ;
Définition de l'unité de temps : toutes les indications de durée et de valeurs d'horloge sont implicitement en secondes. Le trafic est simulé 4 minutes à partir de midi. Les sorties (voir le fichier outspec), seront dirigées dans le répertoire désigné ici.
Fichier des spécifications de sortie : sim0.osp
SAVE DESCRIPTOR voiture ALL f_PS.txt NEW CLOCK position 2 speed 3;
On demande la trace de tous les changements de valeur de la position et de la vitesse de la voiture.
Fichier de de la structure du système : structure
//TRACE PARSING; + I voiture pCar, initialPosition = < pr >< voiture position_initiale >; initialSpeed = < pr >< voiture vitesse_initiale >; state = 1; + C conducteur, ; ; //---------------------------------------- + P course pPC ENTITE_CIBLE = < I >< voiture, >; INIT_EVT DATE_OCCUR = 0; PRIORITE = 5; ; PRCD_EVT DATE_OCCUR = 0; PRIORITE = 10; ; ; + P setCommand pPF ENTITE_CIBLE = < I >; ; //----------------------------------------- + V eventCommand pV DATE_OCCUR = 0; PRIORITE = 9; PROCESS_ACTION = {< P >< ,pPF > (EXEC)}; ;
Création d'une voiture. - affectation de valeurs aux descripteurs à partir des paramètres - création d'un pilote pour la voiture créée et affectation comme composant de la voiture Création du processus de déplacement de la voiture, avec un pas de 1 unité de temps. Attachement du processus à la voiture. Création de des événements d'initialisation et de poursuite du processus. Création du processus ponctuel de détermination de la commande, et attachement au pilote. Création du premier événement de détermination de la commande, en t=0. La priorité 9 le place entre ceux d'initialisation (priorité 0)et de première avancée (priorité 10) du processus de dépacement de la voiture.
Fichier des directives de la simulation : sim0.dir
CHRONO INIT; CHRONO START; RUN; MESSAGE ENDL; CHRONO PAUSE; CHRONO DISPLAY ENDL "duree execution : "; MESSAGE ENDL; CHRONO CLOSE; DISPLAY OUTPUTSPEC ALL; DELETE ALL;
Démarrage du chronomètre. Lancement de la simulation. Affichage de la durée du calcul. Sauvegarde des informations demandées dans le fichier outspec. Récupération de la mémoire non encore désallouée.
Fichier : main.cc
#include##include "UserTypes.h" main (int argc, char* argv[]) { App_ParseMainArguments (argc, argv); ParseParameterFile(argv[1]); InitSimulation(); ParseSimulationFile(argv[2]); ParseOutputSpecFile(argv[3]); ParseStructureFile(argv[4]); ParseDirectiveFile(argv[5]); }
appel : main sim0.par sim0.sim sim0.osp sim0.str sim0.dir Lecture et exploitation des fichiers en entrée.
Trace d'une exécution :
ossau% main sim0.par sim0.sim sim0.osp sim0.str sim0.dir Changement de direction en X = -0.82319 (U = 1) date : 34 Changement de direction en X = 0.235503 (U = 1) date : 86 Changement de direction en X = -1.2 (U = -1) date : 119 ==> Position finale : X = 0.536858, vitesse = 0.0499571 temps simulé = 158 duree execution : 0''019 ossau%
Extrait du fichier de sauvegarde : f_PS.txt
#voiture clock Positio Speed pCar 0 -0.50 -0.001 pCar 1 -0.50 -0.002 pCar 2 -0.51 -0.003 pCar 3 -0.51 -0.005 pCar 4 -0.52 -0.006 pCar 5 -0.52 -0.007 ... ... pCar 32 -0.82 -0.006 pCar 33 -0.82 -0.003 pCar 34 -0.82 0.000 pCar 35 -0.82 0.003 ... ... pCar 84 0.23 0.002 pCar 85 0.24 0.001 pCar 86 0.24 -0.000 pCar 87 0.23 -0.001 ... ... pCar 117 -1.09 -0.060 pCar 118 -1.15 -0.059 pCar 119 -1.20 0.000 pCar 120 -1.20 0.003 ... ... pCar 156 0.44 0.049 pCar 157 0.49 0.049 pCar 158 0.54 0.050