274 lines
7.5 KiB
Python
274 lines
7.5 KiB
Python
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
|
|
|
|
def pause_simulation(self):
|
|
|
|
pass
|
|
|
|
|
|
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
|
|
self.etat_precedent = False #etat precedent du relais
|
|
self.est_point_arret = False #indicateur de point d'arret
|
|
|
|
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):
|
|
etat_precedent = self.haut
|
|
super().update()
|
|
if self.branche.i() >= self.SEUIL:
|
|
self.monte()
|
|
else:
|
|
self.chute()
|
|
|
|
if self.est_point_arret and etat_precedent != self.haut:
|
|
self.graphe.flag_arret_simulation = True
|
|
|
|
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
|