cocosim_python/modele/composants.py

265 lines
7.2 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
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