Catégories
Algorithme Arduino Onduleur Projets Arduino

Onduleur triphasé #6: Algorithme générique – Commande polyphasée

Objectifs

  • Savoir implémenter une commande générique polyphasée
  • Savoir synchroniser son code avec une horloge externe
  • Savoir implémenter la commande MLI ou sPWM (PWM de type sinusoïdal)
  • Savoir implémenter la commande décalée (deux techniques)
  • Savoir le schéma d’un onduleur triphasé
  • Savoir les caractéristiques d’un onduleur
  • Savoir choisir les transistors de la partie puissance
  • Savoir commander un onduleur triphasé
  • Savoir implémenter la commande d’un onduleur triphasé
  • Savoir augmenter les performances de son code & améliorer la fréquence maximale de  l’onduleur
  • Etc.

Applications

  • Commande des Machines polyphasées
  • Réseau polyphasé
  • Alimentation AC à partir d’une source DC (Alimentation à panneaux solaires, batteries, etc.)
  • Conversion de réseaux : Monophasé vers triphasé, monophasé vers un réseau polyphasé, etc.
  • Convertisseur de fréquence d’un réseau 50 Hz vers 60 Hz, 50 Hz vers 400 Hz, etc.
  • Variateur de vitesse des machines asynchrones
  • Etc.

Principe de la synthèse de la commande

Commande générique - Onduleur polyphasée - Schéma de principe 2

 

Réseau Triphasé (N=3)

Commande générique - Onduleur polyphasée - Principe 2

 

Réseau 4-Phases (N=4)

Commande générique - Onduleur Quadriphase

Réseau 5-Phases (N=5)

Commande générique - Onduleur Hexaphase

Stratégie de la commande

Commande générique - Onduleur polyphasée - Stratégie de la commande

Voir le tuto pour les détails techniques

Programme Arduino

La fonction getCmd()

int getCmd(unsigned long *cmdOut, int n_0, int numphase)

La fonction getCmd() permet de synthétiser la commande de l’onduleur en fonction de nombres de phases. Elle prend en entrée le nombre de phases (numphase), un tableau vide et sa taille. Puis, elle renvoie le même tableau rempli et le nombre de séquences dans le tableau. On fait appel à la fonction une seule fois, dans la fonction setup().

int getCmd(unsigned long *cmdOut, int n_0, int numphase) 
{
int n_out=0;
int i,j;
unsigned long SyqT1=0x00000000, SyqT2=0x00000000, Syq0=0x00000000; //32-bits

if ((numphase<=1) || (numphase>15)) return;
for (i=0;i<n_0; i++) cmdOut[i]=0;

/***************************************************/
/*********** Monophasé - Cas particulier ***********/
/***************************************************/
if (numphase==2)
{
cmdOut[0]=0x00000001; //Serial.println(cmd[0], BIN); //1:B01
cmdOut[1]=0x00000002; //Serial.println(cmd[1], BIN); //2:B10
n_out=2;
return n_out;
}

/***************************************************/
/********************* Polyphasé *******************/
/***************************************************/
// A. Génération de la séquence principale
n_out=2*numphase;
SyqT1=0x00000000; Syq0=0x00000001;
for(j=0;j<numphase; j++)
{
SyqT1|=Syq0;
Syq0= Syq0<<1;
}
SyqT2=SyqT1<<(numphase);

// B. Génération des séquences binaires
unsigned long T1i_B0, T2i_B0;
unsigned long T1i[numphase], T2i[numphase], T12i[n_out];
for(int j=0;j<numphase; j++)
{
T1i[j]=0; T2i[j]=0;
}
T1i[0]=SyqT1;T2i[0]=SyqT2;
//Serial.print(T1i[0], BIN); Serial.print(" , "); Serial.println(T2i[0], BIN);

for(j=1;j<numphase; j++)
{
// 1. Extraction du bit b(0)
T1i_B0=(0x00000001&SyqT1);
T2i_B0=(0x00000001&SyqT2);

// 2. Décalage à droite
T1i[j]=SyqT1>>1;
T2i[j]=SyqT2>>1;

// 3. b(n-1) =b(0)
T1i[j]|=T1i_B0<<(n_out-1);
T2i[j]|=T2i_B0<<(n_out-1);

// 4. Mise à jour des séqs Init
SyqT1=T1i[j];
SyqT2=T2i[j];
}

// Combinaision des tableaux
int ii=0, jj=0;
for(j=0;j<n_out; j++)
{
if(j%2==0)
{
T12i[j]=T1i[ii];
ii++;
//Serial.print(j);Serial.print(" , ");Serial.println(T12i[j], BIN);
}
if(j%2==1)
{
T12i[j]=T2i[jj];
jj++;
//Serial.print(j);Serial.print(" , ");Serial.println(T12i[j], BIN);
}
}

// C. Génération des séquences finales
Serial.println("****************************");
Serial.println("T1|T2|T3|T4|T5|T6|T7|T8|T9|... ");
Serial.println("****************************");
unsigned long cmd_i=0;
for(i=0;i<n_out; i++)
{
cmd_i=0;
for(j=0;j<n_out; j++)cmd_i|=(((T12i[j]>>i)&0x1)<<(j));
cmdOut[i]=cmd_i;
for (int k=0;k<32;k++)Serial.print(((cmd_i>>k)&0x1));
Serial.println("");
}
Serial.println("****************************");

return n_out;
}

La fonction setCmd()

void setCmd(unsigned long *cmdOut, int n_0)

la fonction setCmd() sert à transmettre la commande aux ports de sorties. Elle prend en entrée le tableau de commande généré par la fonction getCmd(), puis elle envoie une séquence par itérations de la boucle. La fonction doit être intégrée dans la boucle principale loop() ou dans une routine d’interruption. Elle peut transmettre la commande via 4 ports de 8-bits (PORTA, PORTB, PORC et PORD) au maximal (commande avec 15 phases ==> 32-bits).   Ci-dessous la déclaration et la définition de la fonction.

void setCmd(unsigned long *cmdOut, int n_0) 
{
static int K=0;

// Commenté les lignes non utilisées
PORTA=cmdOut[K] &0x000000ff; // (0) -(1*8-1) --LSB
//PORTB=(cmdOut[K]>>8) &0x000000ff; // (8) -(2*8-1)
//PORTC=(cmdOut[K]>>16)&0x000000ff; // (16)-(3*8-1)
//PORTD=(cmdOut[K]>>24)&0x000000ff; // (24)-(4*8-1) --MSB

// Affichage du contenu des ports sur 8-bits (A commenté)
/*
for (int k=0;k<8;k++) Serial.print(((PORTA>>k)&0x1));Serial.print(",");
for (int k=0;k<8;k++) Serial.print(((PORTB>>k)&0x1));Serial.print(",");
for (int k=0;k<8;k++) Serial.print(((PORTC>>k)&0x1));Serial.print(",");
for (int k=0;k<8;k++) Serial.print(((PORTD>>k)&0x1));Serial.print(",");
Serial.println("");
*/

K++;
if (K==n_0) K=0;
}

Le programme complet


/*
* Algorithme de la commande Symétrique Générique
* La commande peut etre codée sur 32 bits (15 Phases Maximales)
* via 4 ports sur 8-bits (µC 8-bits)
* (ou bien un bus sur 32-bits (µC 32-bits))
*
* PORTA: de (0) à (1*8-1) --LSB
* PORTB: de (8) à (2*8-1)
* PORTC: de (16) à (3*8-1)
* PORTD: de (24) à (4*8-1) --MSB
*
*/

#define T0_us 333 // Période de l'onduleur (Symétrique) : T~n*T0 (µs)
#define Nphs 15 // Nb de phases [2,15]




int n; // Nombre de séquences/ Période
const int nCmd=35; // !!! Ne pas toucher!
unsigned long CmdTab[nCmd]; // !!! Ne pas toucher!



void setup()
{
// Pinout
DDRA =0xff; PORTA=0x00;
//DDRB =0xff; PORTA=0x00;
//DDRC =0xff; PORTA=0x00;
//DDRD =0xff; PORTA=0x00;

// Afficahge
Serial.begin(115200);

// Synthèse de la commande getCmd()
n= getCmd(CmdTab, nCmd, Nphs);
Serial.print("Nseq=");Serial.println(n);
}






void loop()
{
// Génération de la commande setCmd()
setCmd(CmdTab, n);
//delayMicroseconds(T0_us);
}


int getCmd(unsigned long *cmdOut, int n_0, int numphase)
{
int n_out=0;
int i,j;
unsigned long SyqT1=0x00000000, SyqT2=0x00000000, Syq0=0x00000000; //32-bits

if ((numphase<=1) || (numphase>15)) return;
for (i=0;i<n_0; i++) cmdOut[i]=0;

/***************************************************/
/*********** Monophasé - Cas particulier ***********/
/***************************************************/
if (numphase==2)
{
cmdOut[0]=0x00000001; //Serial.println(cmd[0], BIN); //1:B01
cmdOut[1]=0x00000002; //Serial.println(cmd[1], BIN); //2:B10
n_out=2;
return n_out;
}

/***************************************************/
/********************* Polyphasé *******************/
/***************************************************/
// A. Génération de la séquence principale
n_out=2*numphase;
SyqT1=0x00000000; Syq0=0x00000001;
for(j=0;j<numphase; j++)
{
SyqT1|=Syq0;
Syq0= Syq0<<1;
}
SyqT2=SyqT1<<(numphase);

// B. Génération des séquences binaires
unsigned long T1i_B0, T2i_B0;
unsigned long T1i[numphase], T2i[numphase], T12i[n_out];
for(int j=0;j<numphase; j++)
{
T1i[j]=0; T2i[j]=0;
}
T1i[0]=SyqT1;T2i[0]=SyqT2;
//Serial.print(T1i[0], BIN); Serial.print(" , "); Serial.println(T2i[0], BIN);

for(j=1;j<numphase; j++)
{
// 1. Extraction du bit b(0)
T1i_B0=(0x00000001&SyqT1);
T2i_B0=(0x00000001&SyqT2);

// 2. Décalage à droite
T1i[j]=SyqT1>>1;
T2i[j]=SyqT2>>1;

// 3. b(n-1) =b(0)
T1i[j]|=T1i_B0<<(n_out-1);
T2i[j]|=T2i_B0<<(n_out-1);

// 4. Mise à jour des séqs Init
SyqT1=T1i[j];
SyqT2=T2i[j];
}

// Combinaision des tableaux
int ii=0, jj=0;
for(j=0;j<n_out; j++)
{
if(j%2==0)
{
T12i[j]=T1i[ii];
ii++;
//Serial.print(j);Serial.print(" , ");Serial.println(T12i[j], BIN);
}
if(j%2==1)
{
T12i[j]=T2i[jj];
jj++;
//Serial.print(j);Serial.print(" , ");Serial.println(T12i[j], BIN);
}
}

// C. Génération des séquences finales
Serial.println("****************************");
Serial.println("T1|T2|T3|T4|T5|T6|T7|T8|T9|... ");
Serial.println("****************************");
unsigned long cmd_i=0;
for(i=0;i<n_out; i++)
{
cmd_i=0;
for(j=0;j<n_out; j++)cmd_i|=(((T12i[j]>>i)&0x1)<<(j));
cmdOut[i]=cmd_i;
for (int k=0;k<32;k++)Serial.print(((cmd_i>>k)&0x1));
Serial.println("");
}
Serial.println("****************************");

return n_out;
}

void setCmd(unsigned long *cmdOut, int n_0)
{
static int K=0;

// Commenté les lignes non utilisées
PORTA=cmdOut[K] &0x000000ff; // (0) -(1*8-1) --LSB
//PORTB=(cmdOut[K]>>8) &0x000000ff; // (8) -(2*8-1)
//PORTC=(cmdOut[K]>>16)&0x000000ff; // (16)-(3*8-1)
//PORTD=(cmdOut[K]>>24)&0x000000ff; // (24)-(4*8-1) --MSB

// Affichage du contenu des ports sur 8-bits (A commenté)
/*
for (int k=0;k<8;k++) Serial.print(((PORTA>>k)&0x1));Serial.print(",");
for (int k=0;k<8;k++) Serial.print(((PORTB>>k)&0x1));Serial.print(",");
for (int k=0;k<8;k++) Serial.print(((PORTC>>k)&0x1));Serial.print(",");
for (int k=0;k<8;k++) Serial.print(((PORTD>>k)&0x1));Serial.print(",");
Serial.println("");
*/

K++;
if (K==n_0) K=0;
}

Laisser un commentaire