import de fichiers
This commit is contained in:
514
modele/elements.py
Normal file
514
modele/elements.py
Normal file
@@ -0,0 +1,514 @@
|
||||
from modele.exceptions import (WrongElecPropertyException, SurtensionException,
|
||||
SurintensiteException, Dir)
|
||||
|
||||
|
||||
class Element(object):
|
||||
"""
|
||||
Classe mère.
|
||||
Le graphe lui-même est composé de Potentiels fixes (Potentiel), de Noeuds, et de Branches.
|
||||
Les branches contiennent une liste de composants en série.
|
||||
|
||||
Les éléments doivent implémenter quatre méthodes pour le calcul des valeurs :
|
||||
init_cycle est appelée avant chaque cycle, avant l'initialisation de la matrice
|
||||
report_pass_1 est appelée après la première passe pour report des valeurs de la matrice (et avant la construction
|
||||
de la matrice de la deuxième passe)
|
||||
report_pass2 est appelée après la 2e passe pour reporter les valeurs finales calculées
|
||||
update est appelée après le report de la 2e passe, pour pouvoir faire la mise à jour des états des éléments
|
||||
|
||||
"""
|
||||
P_CST, P_NOEUD, P_DLT, P_COND, P_EQVAR, P_BSCLAME = range(6)
|
||||
|
||||
def __init__(self, conf, nom, type_potentiel):
|
||||
self.type_potentiel = type_potentiel
|
||||
self.conf = conf
|
||||
self.nom = nom
|
||||
|
||||
def init_cycle(self):
|
||||
pass
|
||||
|
||||
def passe_calcul(self, solutions, index):
|
||||
pass
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
def etat(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def coherence(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def eq_elts(self):
|
||||
"""
|
||||
Retourne les équipotentiels
|
||||
Par défaut, un seul équipotentiel
|
||||
"""
|
||||
return [self]
|
||||
|
||||
def get_potentiel(self, direction):
|
||||
"""
|
||||
Par défaut, un seul potentiel quel que soit la direction
|
||||
"""
|
||||
return self
|
||||
|
||||
|
||||
class Potentiel(Element):
|
||||
"""
|
||||
Potentiel à 24V ou à 0V
|
||||
"""
|
||||
|
||||
def __init__(self, conf, nom, u=0.0, voisins=None):
|
||||
super().__init__(conf, nom, self.P_CST)
|
||||
self._u = u
|
||||
if voisins is None:
|
||||
voisins = []
|
||||
self._voisins = voisins
|
||||
|
||||
def add_voisins(self, voisins):
|
||||
self._voisins += voisins
|
||||
|
||||
def voisins(self):
|
||||
return self._voisins
|
||||
|
||||
def u(self):
|
||||
return self._u
|
||||
|
||||
def i(self):
|
||||
raise WrongElecPropertyException
|
||||
|
||||
def coherence(self):
|
||||
pass
|
||||
|
||||
def etat(self):
|
||||
return self.u() >= self.conf['USEUIL']
|
||||
|
||||
class PotPulse(Potentiel):
|
||||
def __init__(self, conf, nom, u=0.0, periode=None, voisins=None):
|
||||
super().__init__(conf, nom, u, voisins)
|
||||
if periode is None:
|
||||
periode = self.conf['PULSE_PERIODE']
|
||||
self.periode = periode / self.conf['DT']
|
||||
self.u_max = u
|
||||
self.actif = True
|
||||
self.compteur = 0
|
||||
|
||||
def update(self):
|
||||
self.compteur += 1
|
||||
if self.actif:
|
||||
if self.compteur >= self.periode:
|
||||
self.compteur = 0
|
||||
self._u = 0.
|
||||
self.actif = False
|
||||
else:
|
||||
if self.compteur >= self.periode:
|
||||
self.compteur = 0
|
||||
self._u = self.u_max
|
||||
self.actif = True
|
||||
|
||||
|
||||
class Noeud(Element):
|
||||
"""
|
||||
Nœud du graphe
|
||||
|
||||
self._voisins: liste de (Graphe, polarité) avec polarité = +1 ou -1 pour les branches
|
||||
"""
|
||||
def __init__(self, conf, nom, voisins=None):
|
||||
super().__init__(conf, nom, self.P_NOEUD)
|
||||
self._u = None
|
||||
if voisins is None:
|
||||
voisins = []
|
||||
self._voisins = voisins
|
||||
|
||||
def add_voisins(self, voisins):
|
||||
self._voisins += voisins
|
||||
|
||||
def voisins(self):
|
||||
return self._voisins
|
||||
|
||||
def passe_calcul(self, vect, index):
|
||||
super().passe_calcul(vect, index)
|
||||
self._u = vect[index]
|
||||
|
||||
def u(self):
|
||||
return self._u
|
||||
|
||||
def coherence(self):
|
||||
if abs(self.u()) >= self.conf['UMAX']:
|
||||
raise SurtensionException
|
||||
|
||||
def etat(self):
|
||||
return self.u() >= self.conf['USEUIL']
|
||||
|
||||
|
||||
class Branche(Element):
|
||||
"""
|
||||
Branche du graphe.
|
||||
La branche contient un certain nombre de composants en série, qui peuvent être des relais, tempos, résistances
|
||||
ou contacts (équation). N'est pas utilisable pour les condensateurs.
|
||||
"""
|
||||
def __init__(self, conf, nom, composants):
|
||||
super().__init__(conf, nom, self.P_DLT)
|
||||
self.composants = composants
|
||||
self.amont = None
|
||||
self.aval = None
|
||||
self._i = 0.0
|
||||
|
||||
def add_voisins(self, amont, aval):
|
||||
self.amont = amont
|
||||
self.aval = aval
|
||||
|
||||
def r(self):
|
||||
return sum([x.r for x in self.composants]) + self.conf['RMIN']
|
||||
|
||||
def init_cycle(self):
|
||||
super().init_cycle()
|
||||
[x.init_cycle() for x in self.composants]
|
||||
|
||||
def passe_calcul(self, vect, index):
|
||||
super().passe_calcul(vect, index)
|
||||
self._i = vect[index] # Important de mettre à jour i avant de mettre à jour les composants
|
||||
[x.passe_calcul() for x in self.composants]
|
||||
|
||||
def update(self):
|
||||
super().update()
|
||||
[x.update() for x in self.composants]
|
||||
|
||||
def i(self):
|
||||
return self._i
|
||||
|
||||
def coherence(self):
|
||||
if abs(self.i()) >= self.conf['IMAX']:
|
||||
raise SurintensiteException(f"Dans la branche {self.nom}")
|
||||
|
||||
def etat(self):
|
||||
return self.i() >= self.conf['ISEUIL']
|
||||
|
||||
|
||||
class Condensateur(Element):
|
||||
"""
|
||||
Condensateur.
|
||||
|
||||
La seule truande est que la tension au borne est en réalité calculée avec la charge du cycle précédent.
|
||||
"""
|
||||
def __init__(self, conf, nom, capacite, coef_mul_tension):
|
||||
super().__init__(conf, nom, self.P_COND)
|
||||
self.capacite = capacite
|
||||
self.amont = None
|
||||
self.aval = None
|
||||
self._i = 0.0
|
||||
self.q = 0.0
|
||||
self.q_prec = 0.0
|
||||
self.coef_mul_tension = coef_mul_tension
|
||||
|
||||
def add_voisins(self, amont, aval):
|
||||
self.amont = amont
|
||||
self.aval = aval
|
||||
|
||||
def r(self):
|
||||
raise WrongElecPropertyException
|
||||
|
||||
def init_cycle(self):
|
||||
super().init_cycle()
|
||||
|
||||
def passe_calcul(self, vect, index):
|
||||
super().passe_calcul(vect, index)
|
||||
self._i = vect[index] # Important de mettre à jour i avant de mettre à jour les composants
|
||||
|
||||
def update(self):
|
||||
super().update()
|
||||
self.q_prec = self.q
|
||||
q = self.q + self.i() * self.conf['DT']
|
||||
self.q = q
|
||||
|
||||
def i(self):
|
||||
return self._i
|
||||
|
||||
def coherence(self):
|
||||
if abs(self.i()) >= self.conf['IMAX']:
|
||||
raise SurintensiteException
|
||||
|
||||
def etat(self):
|
||||
return bool(self.i() >= self.conf['ISEUIL'])
|
||||
|
||||
|
||||
class ContactBasculeur(Noeud):
|
||||
"""
|
||||
Nœud du graphe
|
||||
|
||||
self._voisins: liste de (Graphe, polarité) avec polarité = +1 ou -1 pour les branches
|
||||
"""
|
||||
UMAX = 24.5
|
||||
|
||||
class PotentielLocal(Element):
|
||||
def __init__(self, conf, nom, voisins=None):
|
||||
self.lame = None
|
||||
super().__init__(conf, nom, self.P_NOEUD)
|
||||
self._u = None
|
||||
if voisins is None:
|
||||
voisins = []
|
||||
self._voisins = voisins
|
||||
self.etat = False
|
||||
|
||||
def set_lame(self, lame):
|
||||
self.lame = lame
|
||||
|
||||
def add_voisins(self, voisins):
|
||||
self._voisins += voisins
|
||||
|
||||
def set_etat(self, etat):
|
||||
self.etat = etat
|
||||
|
||||
def voisins(self):
|
||||
return self._voisins + ([(self.lame, +1, "foo")] if self.etat else [])
|
||||
|
||||
def passe_calcul(self, vect, index):
|
||||
super().passe_calcul(vect, index)
|
||||
self._u = vect[index]
|
||||
|
||||
def u(self):
|
||||
return self._u
|
||||
|
||||
def coherence(self):
|
||||
if abs(self.u()) >= self.conf['UMAX']:
|
||||
raise SurtensionException
|
||||
|
||||
class Lame(Element):
|
||||
def __init__(self, conf, nom, contact, gauche, droite):
|
||||
self.amont = contact
|
||||
self.aval = None
|
||||
self.gauche = gauche
|
||||
self.droite = droite
|
||||
self.position = None
|
||||
super().__init__(conf, nom, self.P_DLT)
|
||||
self._i = None
|
||||
|
||||
def bascule(self, position):
|
||||
self.position = position
|
||||
if position == Dir.GAUCHE:
|
||||
self.aval = self.gauche
|
||||
else:
|
||||
self.aval = self.droite
|
||||
|
||||
def i(self):
|
||||
return self._i
|
||||
|
||||
def r(self):
|
||||
return self.conf['RMIN']
|
||||
|
||||
# Classe principale
|
||||
def __init__(self, conf, nom, graphe, voisins=None):
|
||||
self.graphe = graphe
|
||||
self.position = None
|
||||
self.potentiel_gauche = self.PotentielLocal(conf, nom + ".G")
|
||||
self.potentiel_droit = self.PotentielLocal(conf, nom + ".D")
|
||||
self.lame = self.Lame(conf, nom + ".L", self, self.potentiel_gauche, self.potentiel_droit)
|
||||
self.potentiel_gauche.set_lame(self.lame)
|
||||
self.potentiel_droit.set_lame(self.lame)
|
||||
self._voisins = [(self.lame, -1, "foo")] + voisins if voisins is not None else []
|
||||
super().__init__(conf, nom, self.P_NOEUD)
|
||||
self.bascule_gauche()
|
||||
|
||||
def eq_elts(self):
|
||||
return [self, self.potentiel_gauche, self.potentiel_droit, self.lame]
|
||||
|
||||
def add_voisins(self, voisins):
|
||||
for vois_tuple in voisins:
|
||||
_, _, connecteur = vois_tuple
|
||||
if connecteur == 'b':
|
||||
self._voisins = [vois_tuple]
|
||||
else:
|
||||
# Les autres connecteurs doivent être câblés vers les ConnecteursLocaux
|
||||
raise "Invalid connector for RelaisBasculeur"
|
||||
|
||||
def voisins(self):
|
||||
return self._voisins
|
||||
|
||||
def bascule_gauche(self):
|
||||
self.position = Dir.GAUCHE
|
||||
self.lame.bascule(self.position)
|
||||
self.potentiel_gauche.set_etat(True)
|
||||
self.potentiel_droit.set_etat(False)
|
||||
|
||||
def bascule_droite(self):
|
||||
self.position = Dir.DROITE
|
||||
self.lame.bascule(self.position)
|
||||
self.potentiel_gauche.set_etat(False)
|
||||
self.potentiel_droit.set_etat(True)
|
||||
|
||||
def get_potentiel(self, direction):
|
||||
"""
|
||||
Par défaut, un seul potentiel quel que soit la direction
|
||||
"""
|
||||
if direction == "b":
|
||||
return self
|
||||
elif direction == "g":
|
||||
return self.potentiel_gauche
|
||||
elif direction == "d":
|
||||
return self.potentiel_droit
|
||||
else:
|
||||
assert False
|
||||
|
||||
def passe_calcul(self, vect, index):
|
||||
super().passe_calcul(vect, index)
|
||||
self.potentiel_droit.passe_calcul(vect, self.graphe.vecteur.index(self.potentiel_droit))
|
||||
self.potentiel_gauche.passe_calcul(vect, self.graphe.vecteur.index(self.potentiel_gauche))
|
||||
self._u = vect[index]
|
||||
|
||||
def u(self):
|
||||
return self._u
|
||||
|
||||
def etat(self):
|
||||
return self.lame.position
|
||||
|
||||
def coherence(self):
|
||||
if abs(self.u()) >= self.conf['UMAX']:
|
||||
raise SurtensionException
|
||||
self.potentiel_droit.coherence()
|
||||
self.potentiel_gauche.coherence()
|
||||
|
||||
|
||||
class ContactDouble(Noeud):
|
||||
"""
|
||||
Nœud du graphe
|
||||
|
||||
self._voisins: liste de (Graphe, polarité) avec polarité = +1 ou -1 pour les branches
|
||||
"""
|
||||
UMAX = 24.5
|
||||
|
||||
class PotentielLocal(Element):
|
||||
def __init__(self, conf, nom, voisins=None):
|
||||
self.lame = None
|
||||
super().__init__(conf, nom, self.P_NOEUD)
|
||||
self._u = None
|
||||
if voisins is None:
|
||||
voisins = []
|
||||
self._voisins = voisins
|
||||
self.etat = False
|
||||
|
||||
def set_lame(self, lame):
|
||||
self.lame = lame
|
||||
|
||||
def add_voisins(self, voisins):
|
||||
self._voisins += voisins
|
||||
|
||||
def set_etat(self, etat):
|
||||
self.etat = etat
|
||||
|
||||
def voisins(self):
|
||||
return self._voisins + ([(self.lame, +1, "foo")] if self.etat else [])
|
||||
|
||||
def passe_calcul(self, vect, index):
|
||||
super().passe_calcul(vect, index)
|
||||
self._u = vect[index]
|
||||
|
||||
def u(self):
|
||||
return self._u
|
||||
|
||||
def coherence(self):
|
||||
if abs(self.u()) >= self.conf['UMAX']:
|
||||
raise SurtensionException
|
||||
|
||||
class Lame(Element):
|
||||
def __init__(self, conf, nom, contact, gauche, droite):
|
||||
self.amont = contact
|
||||
self.aval = None
|
||||
self.repos = gauche
|
||||
self.travail = droite
|
||||
self.position = False # Travail = True
|
||||
super().__init__(conf, nom, self.P_DLT)
|
||||
self._i = None
|
||||
|
||||
def set_position(self, position):
|
||||
self.position = position
|
||||
if position:
|
||||
self.aval = self.travail
|
||||
else:
|
||||
self.aval = self.repos
|
||||
|
||||
def i(self):
|
||||
return self._i
|
||||
|
||||
def r(self):
|
||||
return self.conf['RMIN']
|
||||
|
||||
# Classe principale
|
||||
def __init__(self, conf, nom, graphe, voisins=None, orientation=0):
|
||||
self.graphe = graphe
|
||||
self.orientation = orientation
|
||||
self.potentiel_repos = self.PotentielLocal(conf, nom + ".repos")
|
||||
self.potentiel_travail = self.PotentielLocal(conf, nom + ".travail")
|
||||
self.lame = self.Lame(conf, nom + ".L", self, self.potentiel_repos, self.potentiel_travail)
|
||||
self.potentiel_repos.set_lame(self.lame)
|
||||
self.potentiel_travail.set_lame(self.lame)
|
||||
self._voisins = [(self.lame, -1, "foo")] + voisins if voisins is not None else []
|
||||
super().__init__(conf, nom, self.P_NOEUD)
|
||||
self.lame.set_position(False)
|
||||
|
||||
def eq_elts(self):
|
||||
return [self, self.potentiel_repos, self.potentiel_travail, self.lame]
|
||||
|
||||
def add_voisins(self, voisins):
|
||||
for vois_tuple in voisins:
|
||||
_, _, connecteur = vois_tuple
|
||||
if (self.orientation == 0 and connecteur == 'd') \
|
||||
or (self.orientation == 180 and connecteur == 'g'):
|
||||
self._voisins = [vois_tuple]
|
||||
else:
|
||||
# Les autres connecteurs doivent être câblés vers les ConnecteursLocaux
|
||||
raise "Invalid connector for ContactDouble"
|
||||
|
||||
def voisins(self):
|
||||
return self._voisins
|
||||
|
||||
def get_potentiel(self, direction):
|
||||
"""
|
||||
Par défaut, un seul potentiel quel que soit la direction
|
||||
"""
|
||||
if self.orientation == 0:
|
||||
if direction == "d":
|
||||
return self
|
||||
elif direction == "bg":
|
||||
return self.potentiel_repos
|
||||
elif direction == "hg":
|
||||
return self.potentiel_travail
|
||||
else:
|
||||
assert False
|
||||
elif self.orientation == 180:
|
||||
if direction == "g":
|
||||
return self
|
||||
elif direction == "bd":
|
||||
return self.potentiel_repos
|
||||
elif direction == "hd":
|
||||
return self.potentiel_travail
|
||||
else:
|
||||
assert False
|
||||
else:
|
||||
assert False
|
||||
|
||||
def passe_calcul(self, vect, index):
|
||||
super().passe_calcul(vect, index)
|
||||
self.potentiel_travail.passe_calcul(vect, self.graphe.vecteur.index(self.potentiel_travail))
|
||||
self.potentiel_repos.passe_calcul(vect, self.graphe.vecteur.index(self.potentiel_repos))
|
||||
self._u = vect[index]
|
||||
|
||||
def u(self):
|
||||
return self._u
|
||||
|
||||
def etat(self):
|
||||
return self.lame.position
|
||||
|
||||
def coherence(self):
|
||||
if abs(self.u()) >= self.conf['UMAX']:
|
||||
raise SurtensionException
|
||||
self.potentiel_travail.coherence()
|
||||
self.potentiel_repos.coherence()
|
||||
|
||||
def active(self):
|
||||
self.lame.set_position(True)
|
||||
self.potentiel_travail.set_etat(True)
|
||||
self.potentiel_repos.set_etat(False)
|
||||
|
||||
def desactive(self):
|
||||
self.lame.set_position(False)
|
||||
self.potentiel_travail.set_etat(False)
|
||||
self.potentiel_repos.set_etat(True)
|
||||
Reference in New Issue
Block a user