
import numpy as np
                   
class MoteurSynchrone:
    def __init__(self,r,L,Phi0,J,G0,a,alphaE):
        self.r = r
        self.L = L
        self.Phi0 = Phi0
        self.J = J
        self.Gamma0 = G0
        self.a = a
        self.Npoles = 8
        self.angleAimant = 360/self.Npoles
        self.DEG2RAD = np.pi/180
        self.RAD2DEG = 180/np.pi
        self.theta = 0 # angle rotor en degrés
        self.omega = 0 # vitesse angulaire en rad/s
        self.etatCapt = [0,0,0]
        self.etatPont = 0 # état 0..5
        self.capt2etats = [2,0,1,4,3,5] # table état des capteurs -> état du pont
        self.indice_m = 0
        self.indice_n = 0
        self.indice_p = 0
        self.tabIndice_m = [0,0,1,1,2,2]
        self.tabIndice_n = [1,2,2,0,0,1]
        self.tabIndice_p = [2,1,0,2,1,0]
        self.alphaE = alphaE # tension effective
        self.Gamma = 0 # couple moteur
        self.tensions = [0,0,0]  
        self.courants = [0,0,0]
        self.e = [0,0,0] # f.é.m.
        self.VN = 0
        self.potentielsBornes = [0,0,0] # 1 : potentiel haut, 0 : potentiel nul, -1 : potentiel libre
        self.courantDiode = False # courant dans une diode de roue libre
        self.seuilDiode = 0.8
              
                   
    def etatCapteur(self,beta):
        if beta >= self.theta-self.angleAimant/2:
            if int((beta-self.theta+self.angleAimant/2)/self.angleAimant)%2==0:
                return 1
            else:
                return 0
        else:
            if int((beta-self.theta-self.angleAimant/2)/self.angleAimant)%2==0:
                return 1
            else:
                return 0
                   
    def determinerEtatPont(self):
        cap1 = self.etatCapteur(30)
        cap2 = self.etatCapteur(60)
        cap3 = self.etatCapteur(90)
        bin = cap1*4+cap2*2+cap3
        if (self.etatCapt[0] != cap1 or  self.etatCapt[1]!=cap2 or self.etatCapt[2]!=cap3) and bin>0 and bin<=6:
            self.etatCapt = [cap1,cap2,cap3]
            if self.capt2etats[bin-1] != (self.etatPont+1)%6:
                print("Erreur :  étape sautée")
            self.etatPont = self.capt2etats[bin-1]
            self.indice_m = self.tabIndice_m[self.etatPont]
            self.indice_n = self.tabIndice_n[self.etatPont]
            self.indice_p = self.tabIndice_p[self.etatPont]
            self.courantDiode = True # la diode de la borne p est passante
            if self.potentielsBornes[self.indice_p] ==1 : self.potentielVp = -self.seuilDiode
            else: self.potentielVp = self.alphaE + self.seuilDiode
            self.potentielsBornes[self.indice_m] = 1
            self.potentielsBornes[self.indice_n] = 0
            self.potentielsBornes[self.indice_p] = -1
            
            
            
            return 1 # l'état a changé
        return 0 # l'état n'a pas changé
                   
    def pasEuler(self):
        sinphi1 = np.sin(4*self.theta*self.DEG2RAD)
        sinphi2 = np.sin((4*self.theta-120)*self.DEG2RAD)
        sinphi3 = np.sin((4*self.theta+120)*self.DEG2RAD)
        A = self.omega*4*self.Phi0
        self.e = [A*sinphi1,A*sinphi2,A*sinphi3]
        em = self.e[self.indice_m]
        en = self.e[self.indice_n]
        ep = self.e[self.indice_p]
        Im = self.courants[self.indice_m]
        In = self.courants[self.indice_n]
        Ip = self.courants[self.indice_p]
        if self.courantDiode: # la bobine (p) se décharge dans une des deux diodes
            Vp = self.potentielVp
            self.VN = 1/3*(self.alphaE+Vp+em+en+ep)
            deriv_Im = 1/self.L*(self.alphaE-self.VN-self.r*Im+em)
            deriv_In = 1/self.L*(-self.VN-self.r*In+en)
            deriv_Ip = 1/self.L*(Vp-self.VN-self.r*Ip+ep)
            deriv_theta = self.omega*self.RAD2DEG
            self.Gamma = -4*self.Phi0*(self.courants[0]*sinphi1+self.courants[1]*sinphi2+self.courants[2]*sinphi3)
            deriv_omega = 1/self.J*(self.Gamma-self.Gamma0*(self.omega>0)-self.a*self.omega)
            Im += self.h*deriv_Im
            In += self.h*deriv_In 
            Ip += self.h*deriv_Ip
            self.courantDiode = not( (Vp==-self.seuilDiode and Ip<=0) or (Vp==self.alphaE+self.seuilDiode and Ip>=0))
        else: # le courant est nul dans la bobine (p)
            In = -Im
            Ip = 0
            self.VN = 1/2*(self.alphaE+em+en)
            deriv_Im = 1/self.L*(self.alphaE-self.VN-self.r*Im+em)
            deriv_theta = self.omega*self.RAD2DEG
            self.Gamma = -4*self.Phi0*(self.courants[0]*sinphi1+self.courants[1]*sinphi2+self.courants[2]*sinphi3)
            deriv_omega = 1/self.J*(self.Gamma-self.Gamma0*(self.omega>0)-self.a*self.omega)
            Im += self.h*deriv_Im
            In = -Im
            Vp = self.VN-ep
        self.courants[self.indice_m] = Im
        self.courants[self.indice_n] = In 
        self.courants[self.indice_p] = Ip 
        self.theta += self.h*deriv_theta
        self.omega += self.h*deriv_omega 
        self.tensions[self.indice_m] = self.alphaE
        self.tensions[self.indice_n] = 0
        self.tensions[self.indice_p] = Vp
        
                   
    def initialiser(self):
        self.courants = [0,0,0]
        self.tensions = [0,0,0]
        self.theta = 0
        self.omega = 0
                   
    def simulation(self,tmax,h):
        t = 0
        i1 = []
        i2 = []
        i3 = []
        V1 = []
        V2 = []
        V3 = []
        e1 = []
        e2 = []
        e3 = []
        VN = []
        temps = []
        theta = []
        Gamma = []
        omega = []
        Ps = []
        self.h = h
        while t<tmax:
            i1.append(self.courants[0])
            i2.append(self.courants[1])
            i3.append(self.courants[2])
            V1.append(self.tensions[0])
            V2.append(self.tensions[1])
            V3.append(self.tensions[2])
            e1.append(self.e[0])
            e2.append(self.e[1])
            e3.append(self.e[2])
            VN.append(self.VN)
            theta.append(self.theta)
            omega.append(self.omega)
            Gamma.append(self.Gamma)
            Ps.append(self.courants[self.indice_m]*self.alphaE)
            temps.append(t)
            t += self.h
            self.determinerEtatPont()
            self.pasEuler()
            
        return np.array(temps),np.array(i1),np.array(i2),np.array(i3),np.array(V1),np.array(V2),np.array(V3),np.array(e1),np.array(e2),np.array(e3),np.array(VN),np.array(theta),np.array(omega),np.array(Gamma),np.array(Ps)
            
                   
    def simulationVide(self,tmax,h):
        t = 0
        self.h = h
        while t<tmax:
            t += self.h
            self.determinerEtatPont()
            self.pasEuler()
            
    
    
    def pasCalculSansSource(self):
        sinphi1 = np.sin(4*self.theta*self.DEG2RAD)
        sinphi2 = np.sin((4*self.theta-120)*self.DEG2RAD)
        sinphi3 = np.sin((4*self.theta+120)*self.DEG2RAD)
        A = self.omega*4*self.Phi0
        self.e = [A*sinphi1,A*sinphi2,A*sinphi3]
        em = self.e[self.indice_m]
        en = self.e[self.indice_n]
        ep = self.e[self.indice_p]
        deriv_theta = self.omega*self.RAD2DEG
        self.theta += self.h*deriv_theta
        self.tensions[self.indice_m] = -em
        self.tensions[self.indice_n] = -en
        self.tensions[self.indice_p] = -ep
                   
    def simulationSansSource(self,omega,tmax,h):
        t = 0
        V = []
        temps = []
        theta = []
        self.h = h 
        self.omega = omega
        while t < tmax:
            V.append(self.tensions[self.indice_m]-self.tensions[self.indice_n])
            theta.append(self.theta)
            temps.append(t)
            t += self.h
            self.determinerEtatPont()
            self.pasCalculSansSource()
            
        return np.array(temps),np.array(V),np.array(theta)

                   