SPWM para control motor trifásico

Buenas a todos!!
Veréis estoy trabajando en el control de velocidad de un motor trifásico mediante la técnica SPWM (sine pulse width modulation), ello consiste en comparar una señal triangular con una senoidal para así obtener la tensión de disparo de los transistores. A grosso modo lo que tenemos son 2 señales tipo boolean, entre las cuáles debe haber un tiempo muerto de unos 4 microsegundos, para así evitar cortocircuitos. Lo que queríamos saber es cuánto tiempo puede tardar en hacer la conmutación de los pines digitales, ya que(como se aprecia en la captura adjuntada más abajo), tarda unos 10 microsegundos en realizar dicha conmutación. Actualmente estamos empleando una placa Arduino Mega 2560 R3. Os dejo el código para que podáis ver mas o menos cómo estamos intentando hacerlo. Saludos y gracias de antemano.

 //Funcion SPWM con 2 señales

float Atri=5;       //Amplitud triangular
float Ttri=0.001;       //Periodo triangular
float t2=0;          //Variable de apoyo funcion triangular
unsigned long int t1=0;            //Variable de apoyo funcion triangular
float Tiempo=0;      //Variable tiempo
boolean S1 =false;    //Variable tipo boolean
boolean S2 =false;    //Variable tipo boolean

boolean flag1=false;
boolean Aflag1=false; 

double ysin=0;       // Funcion seno 1
double ytri=0;       // Funcion triangular
const float pi=3.1416;    //Constante pi
float fnom=50;        //Frecuencia nominal
float Vnom=5;         //Tension nominal
float fsin=0;         // Frecuencia senoidal
float Vsin=0;         //Tension senoidal

////////////////////////////////*INICIAMOS EL SETUP*/////////////////////////
void setup()
{
  Serial.begin(9600);          //  Inicialización del modulo Serial.
}

//////////////////////////*INICIAMOS EL PROGRAMA PRINCIPAL*///////////////////////////////
void loop()
{
  Tiempo= (double (micros()))/(1000000);
    
 
  
Vsin=Vnom;
   t1=Tiempo/Ttri;                            //Iniciamos la funcion triangular
        t2=Tiempo-t1*Ttri;
        if (t2 <= (Ttri/2))
          {
            ytri=2*Atri*t2/Ttri-Atri/2;
          }
        else
        {
          ytri=-2*Atri*t2/Ttri + 3*Atri/2;
        }
        
       ysin=Vsin*sin(2*pi*fsin*Tiempo);            // Iniciamos la funcion senoidal 1    
      
       if  (ysin > ytri)                           // Comparamos la funcion senoidal y la triangular
   {         
          flag1=true;

          if (flag1 != Aflag1)
          { S2=!S2;
            
            digitalWrite(29,S2);

            delayMicroseconds(2);
            S1=!S1;
            digitalWrite(28,S1);
          }
      }
       else
      {
        flag1=false;
          if (flag1 != Aflag1)
          {
            S1=!S1;
            digitalWrite(28,S1);
            delayMicroseconds(2);
            S2=!S1;
            digitalWrite(29,S2);
            }
          }       
       
        Aflag1=flag1;
      }

Hola, la captura no se cargó, y sería bueno que precises cuando la subas nuevamente de que momento hablas.
Hablas de la conmutación 0-1 o 1-0 (perdon por la obviedad)?

Veo en tu código muchas multiplicaciones : atento con eso.. y con los tiempos que insuman.

Cuando trabajas con SPWM se suelen usar tablas que evitan esas cuentas que insumen tiempo.
Las tablas estan cargadas con los valores que tomará en cada punto.

Algo que no veo... es el uso de PWM o sea, no inicializas timers, si lo intentas hacer como me parece usando software para comandar las salidas creo que vas a tener problemas trabajando con los MOSFET.
Luego te paso un código trifásico que tengo guardado.

Muchas gracias por tu rápida respuesta.
Pues el tiempo de conmutación de 0-1 y de 1-0 es prácticamente el mismo como se ve en la imagen(espero que ahora sí que se vea).

Otra cuestión que no he comprendido muy bien es lo de usar tablas en lugar de las operaciones. Lo que queremos con este código es poder variar la frecuencia de forma lineal con respecto a la tensión para que el motor puede cambiar su velocidad, esto se hace mediante un potenciómetro y por tanto los valores van cambiando en función de la resistencia que adopte el mismo, por consiguiente no sé si sería posible usar las tablas.

Te agradecería enormemente ese código. Un saludo.

bueno aca esta el código que te había prometido

#include "avr/pgmspace.h"
#include "avr/io.h"

// Look Up table of a single sine period divied up into 256 values. Refer to PWM to sine.xls on how the values was calculated
PROGMEM  prog_uchar sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124};
  
  
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
int PWM_OUT_1	= 11; // PWM output on pin 11
int PWM_OUT_2	= 10; // PWM output on pin 10
int PWM_OUT_3	= 12; // PWM output on pin 9
int LED_PIN		= 13; // LED status on pin 13
int TEST_PIN	=  7; // Scope trigger on pin 7
int POTEN_IN	= A0; // Potentiometer on pin 0
int OFFSET_1	= 85; // Offset for second-phase
int OFFSET_2	= 170; // Offset for third-phase
float dfreq;
const double refclk = 31376.6; // measured
const uint64_t twoTo32 = pow(2, 32); // compute value at startup and use as constant
// variables used inside interrupt service declared as voilatile
volatile uint8_t icnt; // var inside interrupt
volatile uint8_t icnt1; // var inside interrupt
volatile uint8_t c4ms; // counter incremented every 4ms
volatile uint32_t phase_accum; // pahse accumulator
volatile uint32_t tword_m; // dds tuning word m
//******************************************************************
void setup()
{
	pinMode(LED_PIN, OUTPUT); // sets the digital pin as output
	Serial.begin(9600); // connect to the serial port
	Serial.println("DDS Test");

	pinMode(TEST_PIN, OUTPUT); // sets the digital pin as output
	pinMode(PWM_OUT_1, OUTPUT); // PWM output / frequency output
	pinMode(PWM_OUT_2, OUTPUT); // PWM output / frequency output
	pinMode(PWM_OUT_3, OUTPUT); // PWM output / frequency output
	// Setup the timers
	setup_timer1();
	setup_timer2();
	// disable interrupts to avoid timing distortion
	cbi (TIMSK0, TOIE0); // disable Timer0 !!! delay() is now not available
	sbi (TIMSK2, TOIE2); // enable Timer2 Interrupt
	dfreq = 50.0; // initial output frequency = 1000.0 Hz
	tword_m = twoTo32 * dfreq / refclk; // calulate DDS new tuning word
}
//******************************************************************
void loop()
{
  long frequency = twoTo32 * analogRead(POTEN_IN) / refclk; // calulate DDS new tuning word
  noInterrupts () ;
  tword_m = frequency ; // copy quickly with interrupts masked
  interrupts () ;
}
//******************************************************************
// timer1 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz clock
void setup_timer1(void)
{
	// Timer1 Clock Prescaler to : 1
	sbi (TCCR1B, CS10);
	cbi (TCCR1B, CS11);
	cbi (TCCR1B, CS12);
	// Timer0 PWM Mode set to Phase Correct PWM
	cbi (TCCR1A, COM1A0); // clear Compare Match
	sbi (TCCR1A, COM1A1);
	cbi (TCCR1A, COM1B0); // clear Compare Match
	sbi (TCCR1A, COM1B1);
	sbi (TCCR1A, WGM10); // Mode 1 / Phase Correct PWM
	cbi (TCCR1A, WGM11);
	cbi (TCCR1B, WGM12);
	cbi (TCCR1B, WGM13);
}

//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM, 16000000/512 = 31.25kHz clock
void setup_timer2()
{
	// Timer2 Clock Prescaler to : 1
	sbi (TCCR2B, CS20);
	cbi (TCCR2B, CS21);
	cbi (TCCR2B, CS22);
	// Timer2 PWM Mode set to Phase Correct PWM
	cbi (TCCR2A, COM2A0); // clear Compare Match
	sbi (TCCR2A, COM2A1);
	sbi (TCCR2A, WGM20); // Mode 1 / Phase Correct PWM
	cbi (TCCR2A, WGM21);
	cbi (TCCR2B, WGM22);
}
//******************************************************************
// Timer2 Interrupt Service at 31.25kHz = 32us
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect)
{
	sbi(PORTD, TEST_PIN); // Test / set PORTD,TEST_PIN high to observe timing with a oscope
	phase_accum += tword_m; // soft DDS, phase accu with 32 bits
	icnt = phase_accum >> 24; // use upper 8 bits for phase accu as frequency information
	OCR2A = pgm_read_byte_near(sine256 + icnt); // read value fron ROM sine table and send to PWM DAC
	OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_1));
	OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(icnt + OFFSET_2));
	if (icnt1++ == 125) // increment variable c4ms every 4 milliseconds
	{
		c4ms++;
		icnt1 = 0;
	}
	cbi(PORTD, TEST_PIN); // reset PORTD,TEST_PIN
}

No es perfecto pero es una buena aproximación.

Mira la tabla, los indices que explorar cada tabla con el defasaje de 120 grados incluido

olvidé lo mas importante
acá esta el link de donde viene este código, yo solamente extracté el que resume todas las mejoras.
Aunque no esta listo te permite tener una buena aproximación a lo que buscas.
http://forum.arduino.cc/index.php?topic=236778.75