from modele.exceptions import NonPolariseException, Dir class Composant(object): def __init__(self, conf, nom): """ Un composant doit a minima savoir donner une résistance """ self.branche = None # Pour récupérer l'intensité dans la branche self.nom = nom self.conf = conf self.r = None def init_cycle(self): """ Initialisation du composant avant la 1ere passe de calcul. Pour la plupart des composants (ceux qui se calculent en une seule passe) on ne fait rien. N'est utile que pour les composants se calculant en plusieurs passes (diodes...). """ pass def passe_calcul(self): """ Initialisation du composant apres la 1ere passe de calcul. Pour la plupart des composants (ceux qui se calculent en une seule passe) on ne fait rien. N'est utile que pour les composants se calculant en plusieurs passes (diodes...). """ pass def update(self): # Par défaut ne fait rien pass def reverse(self): """ Permet de retourner les composants polarisés (s'ils sont préfixés par "!") """ raise NonPolariseException def etat(self): raise NotImplementedError class Contact(Composant): def __init__(self, conf, nom, contact_type): super().__init__(conf, nom) self.ouvert = None self.ouvre() self.type = contact_type def ouvre(self): self.ouvert = True self.r = self.conf['RMAX'] def ferme(self): self.ouvert = False self.r = self.conf['RMIN'] def etat(self): return not self.ouvert def bascule(self): if self.ouvert: self.ferme() else: self.ouvre() class Resistance(Composant): def __init__(self, conf, nom, valeur): super().__init__(conf, nom) self.RDEFAULT = self.conf["RES_DEFAULT"] if valeur is None: self.r = self.RDEFAULT else: self.r = valeur def set_r(self, valeur): self.r = valeur def etat(self): return None class Lampe(Resistance): def __init__(self, conf, nom): self.RLAMPE = conf["RES_LAMPE"] self.SEUIL = conf["SEUIL_LAMPE"] super().__init__(conf, nom, self.RLAMPE) self.haut = False self.chute() def monte(self): self.haut = True def chute(self): self.haut = False def update(self): super().update() if abs(self.branche.i()) >= self.SEUIL: self.monte() else: self.chute() def etat(self): return self.haut class Relais(Composant): def __init__(self, conf, nom, graphe): super().__init__(conf, nom) self.graphe = graphe self.r = self.conf["RES_RELAIS"] self.SEUIL = self.conf["SEUIL_RELAIS"] prefix = nom.split('.') self._contacts_travail = [] self._contacts_repos = [] self._contacts_double = [] self.haut = False def add_travail(self, nom): self._contacts_travail.append(nom) def add_repos(self, nom): self._contacts_repos.append(nom) def add_double(self, nom): self._contacts_double.append(nom) def monte(self): self.haut = True for nom in self._contacts_repos: self.graphe[nom].ouvre() for nom in self._contacts_travail: self.graphe[nom].ferme() for nom in self._contacts_double: self.graphe[nom].active() def chute(self): self.haut = False for nom in self._contacts_repos: self.graphe[nom].ferme() for nom in self._contacts_travail: self.graphe[nom].ouvre() for nom in self._contacts_double: self.graphe[nom].desactive() def update(self): super().update() if self.branche.i() >= self.SEUIL: self.monte() else: self.chute() def etat(self): return self.haut class DemiRelaisBasculeur(Composant): def __init__(self, conf, nom, graphe, cote): super().__init__(conf, nom) self.SEUIL = self.conf["SEUIL_RELAIS"] self.r = self.conf["RES_RELAIS"] self._contacts_basc = [] self.haut = False self.cote = cote self.graphe = graphe def add_contact(self, nom): self._contacts_basc.append(nom) def monte(self): self.haut = True if self.cote == Dir.GAUCHE: for nom in self._contacts_basc: self.graphe.elements[nom].bascule_gauche() elif self.cote == Dir.DROITE: for nom in self._contacts_basc: self.graphe.elements[nom].bascule_droite() else: assert False def chute(self): self.haut = False def update(self): super().update() if self.branche.i() >= self.SEUIL: self.monte() else: self.chute() def etat(self): return self.haut class Tempo(Composant): """ Tempo type "bilame piloté par le temps" """ def __init__(self, conf, nom, tempo_blocage, tempo_liberation): super().__init__(conf, nom) self.SEUIL = self.conf["SEUIL_TEMPO"] self.h_trans = 0 # heure de la transition self.h = 0 # heure courante self.i_prec = 0.0 # intensité précédente self.tempo_blocage = tempo_blocage / self.conf["DT"] # durée de la tempo de blocage self.tempo_liberation = tempo_liberation / self.conf["DT"] # durée de la tempo de blocage self.blocage = False self.r = self.conf['RMIN'] def update(self): if self.blocage: if self.h - self.h_trans >= self.tempo_liberation: self.h_trans = self.h self.blocage = False self.r = self.conf["RMIN"] else: if self.branche.i() >= self.SEUIL: if self.i_prec < self.SEUIL: self.h_trans = self.h # On mémorise l'heure de la transition if self.h - self.h_trans >= self.tempo_blocage - 1: self.r = self.conf["RMAX"] self.blocage = True self.h_trans = self.h # On mémorise l'heure à laquelle on bloque else: pass # On est au-delà du seuil mais la tempo n'est pas échue self.i_prec = self.branche.i() self.h += 1 @property def ouvert(self): return self.blocage def etat(self): return not self.blocage class Diode(Composant): def __init__(self, conf, nom): super().__init__(conf, nom) self.r = self.conf["RMAX"] self.reversed = False # La diode est dans le sens opposé à la branche def init_cycle(self): self.r = self.conf["RMAX"] def passe_calcul(self): if (not self.reversed and (self.branche.amont.u() > self.branche.aval.u())) \ or (self.reversed and (self.branche.amont.u() < self.branche.aval.u())): self.r = self.conf["RMIN"] else: self.r = self.conf["RMAX"] def reverse(self): self.reversed = True def etat(self): return None