Catégories
Arduino électronique Onduleur Projets Arduino Projets électroniques

Projet Onduleur Triphasé #4: Commande sPWM (MLI)

Objectifs

  • 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

  • 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.

Fonctionnement

La commande MLI (Modulation de Largeur d’Impulsion) de type sinusoïdal sPWM est largement utilisée dans la commande des convertisseurs (AC/DC, DC/AC, AC/AC, etc.). Elle permet de synthétiser un signal qui s’approche du signal sinusoïdal à partir d’un signal tout ou rien (signal carré). En effet, un signal carré est une combinaison linaire d’une multitude des harmoniques (f0, 2f0, 3f0,…, nf0). Un signal carré est simple à générer via les composants de puissances. En revanche, il n’est pas efficace en termes du rendement et pertes dus aux harmoniques secondaires. Le transfert de puissance est maximale lorsque le signal est constitué d’une seule harmonique (sinus pur).

Avant d’entamer la suite, veuillez consulter les parties précédentes.

Les aspects théoriques de la modulation MLI sont abordés dans le projet onduleur monophasé. Concernant l’onduleur triphasé, il suffit de générer trois sinusoïdes décalées de 60°. La technique consiste d’utiliser un seul tableau pour les phases contenant les échantillons d’une demi période du signal sinusoïdal. Ensuite, utiliser trois indices décalés les uns par rapport aux autres de 60°. Si le tableau est constitué de N échantillons, alors le décalage 60° est équivalent à N/6 échantillons. Durant l’initialisation des indices, on définit : I_Phase1=0,  I_Phase2=N/6 et I_Phase3=2*N/6. Voir le tuto pour plus de détails.

Programme complet

/*
* Commande Symétrique : SetCMD1() & SetCMD2()
* Commande Décalée : SetCMD3() & SetCMD4()
* Commande PWM(MLI) : Voir le programme
*/

#define Tr11 22 // Transistor 1/Bras 1
#define Tr12 23 // Transistor 2/Bras 1
#define Tr21 24 // Transistor 1/Bras 2
#define Tr22 25 // Transistor 2/Bras 2
#define Tr31 26 // Transistor 1/Bras 3
#define Tr32 27 // Transistor 2/Bras 3

#define T0_us 333 // Période de l'onduleur (Symétrique) : T=6*T0 (µs)
// Période de l'onduleur (Décalée) : T=12*T0 (µs)
// sPWM: Période d'incrémentation du Timer
// sPWM: Période globale T=2*N*T0_us => F=1/F: Fréquence de l'Onduleur
/* Params sPWM */
#define N 64 // Niveaux de l'onduleur : Nombre d’échantillons (format 2^n)
#define TimerStep 13 // Pas d'incrémentation du Timer rapide (>>1)


int Trans[6]; // Ou bien PORTA
unsigned long MedSine[N];
unsigned long TimerSPWM=0;
unsigned long i_sin[3]={0,0,0};
bool sPWM_l[3]={false,false,false};
bool sPWM_r[3]={true,true,true};
bool sinePolar[3]={false,false,false};
double sine_val=0.0, A=0.0;
int Nbit=0; // Amplitude du signal sinusoïdal 2^8

void setup()
{
// Pinout
Trans[0]=Tr11; Trans[1]=Tr12;
Trans[2]=Tr21; Trans[3]=Tr22;
Trans[4]=Tr31; Trans[5]=Tr32;
for (int i=0;i<6; i++)
{
pinMode(Trans[i], OUTPUT);
digitalWrite(Trans[i], LOW);
}
// Ou bien: Init du port A en sortie
//DDRA =0xff; PORTA=0x00;

// Codage binaire de l'amplitude
Nbit=(int)round((log((float)N)/log(2.0)));

// Init Timers // Déphasage de 60°/Bras (60°=>T/6)
i_sin[0]=0; // Bras 1 - 0°
i_sin[1]=round((float)N/6.0); // Bras 2 - 60°
i_sin[2]=round(2.0*(float)N/6.0); // Bras 3 - 120°

// Génération du signal sinusoïdal : 1/2 Période (2*N échantillons/période)
A=(double)(pow(2.0,(double)Nbit)-1.0);
for (int i=0; i<N; i++)
{
sine_val=A*sin(PI*(double)i/(double)(N));
MedSine[i]=(int)(abs(floor(sine_val)));
}

// Affichage
Serial.begin(9600);
pinMode(3,OUTPUT);
}

void loop()
{
/*
SetCMD1(Trans);
SetCMD2(Trans);
SetCMD3(Trans);
SetCMD4(Trans);
delayMicroseconds(T0_us);
return;
*/

/*
delayMicroseconds(11);
digitalWrite(3, sinePolar[0]);
*/

// Prévisualisation des signaux du Bras 1 + sin(t)
/*
Serial.print(MedSine[i_sin[0]]); Serial.print(",");
Serial.print(i_sin[0]); Serial.print(",");
Serial.print(A*sPWM_l[0]); Serial.print(",");
Serial.println(-A*sPWM_r[0]);
*/

// Visualisation des signaux de l'onduleur
/*
Serial.print(sPWM_l[0]+0); Serial.print(",");
Serial.print(sPWM_r[0]+1); Serial.print(",");
Serial.print(sPWM_l[1]+2); Serial.print(",");
Serial.print(sPWM_r[1]+3); Serial.print(",");
Serial.print(sPWM_l[2]+4); Serial.print(",");
Serial.println(sPWM_r[2]+5);
*/

// Incrémentation du Timer: Compteur rapide (signal triangulaire)
TimerSPWM+=TimerStep;
if (TimerSPWM>N) TimerSPWM=0;

// Génération de la commande
for (int i=0; i<3; i++)
{
// 1. Incrémentation du Timer du signal : Compteur long (signal sinusoïdal)
i_sin[i]+=1;
if (i_sin[i]>N) i_sin[i]=0;

// 2. Inversion de la polarité de la période
if(!i_sin[i]) sinePolar[i]=!sinePolar[i];

// 3. Génération des signaux PWM
if(sinePolar[i]) // Période (+)
{
sPWM_l[i] =MedSine[i_sin[i]] > TimerSPWM;
sPWM_r[i] =false;
}
else // Période (-)
{
sPWM_l[i] = false;
sPWM_r[i] =MedSine[i_sin[i]] > TimerSPWM;
}
}

// Envoie des signaux au Port A
PORTA=(B00000001*sPWM_l[0])+ (B00000010*sPWM_r[0])+
(B00000100*sPWM_l[1])+ (B00001000*sPWM_r[1])+
(B00010000*sPWM_l[2])+ (B00100000*sPWM_r[2]);
}



void SetCMD1( int *pins)
{
static int I=0;
const bool Cmd[6][6]={{0,1,1,0,0,1},
{1,0,1,0,0,1},
{1,0,0,1,0,1},
{1,0,0,1,1,0},
{0,1,0,1,1,0},
{0,1,1,0,1,0}};

for (int i=0;i<6; i++) digitalWrite(pins[i], Cmd[I][i]);
I++; I%=6;

return 0;
}





void SetCMD2( int *pins)
{
static unsigned char I=0;
const unsigned char Cmd[6]={B00011001,
B00101001,
B00100101,
B00100110,
B00010110,
B00011010};

PORTA=Cmd[I];
I++;

//I%=6; // Fréquence: +
//I=I*(I<6); // Fréquence: ++
if (I>=6)I=0; // Fréquence: +++

return 0;
}



void SetCMD3( int *pins)
{
static unsigned char I=0;
const bool Cmd[12][6]={
{0,1,1,0,0,0},
{0,0,1,0,0,1},
{0,0,1,0,0,1},
{1,0,0,0,0,1},
{1,0,0,0,0,1},
{1,0,0,1,0,0},
{1,0,0,1,0,0},
{0,0,0,1,1,0},
{0,0,0,1,1,0},
{0,1,0,0,1,0},
{0,1,0,0,1,0},
{0,1,1,0,0,0},
};

for (int i=0;i<6; i++) digitalWrite(pins[i], Cmd[I][i]);
I++;
if (I>=12)I=0;

return 0;
}


void SetCMD4( int *pins)
{
static unsigned char I=0;
const unsigned char Cmd[12]= {
B00011000,
B00001001,
B00001001,
B00100001,
B00100001,
B00100100,
B00100100,
B00000110,
B00000110,
B00010010,
B00010010,
B00011000
};

PORTA=Cmd[I];
I++;
if (I>=12)I=0;

return 0;
}

On verra dans le prochain tuto comment utiliser une horloge externe de l’onduleur. N’oublie pas un commentaire pour nous encourager et contribuer au développement du blog.

4 réponses sur « Projet Onduleur Triphasé #4: Commande sPWM (MLI) »

Bonjour
Merci pour ces tutos que je trouve très bien faits.
Pourquoi le déphasage entre les 3 bras (I_Phase1,2,3) est de 60° alors qu’en tri les phases sont déphasées de 120°.
Je dois fabriquer un onduleur en tri pour produire du 115V 400 Hz et vos tutos constituent une tres bonne base de départ.
Merci !

Bonjour, avec plaisir. Le déphasage des signaux de commandes est diffèrent de celui des phases! Essaye d’observer l’ensemble des tutos depuis le début pour plus d’explications.

Laisser un commentaire