Generar SPWM para inversor trifásico

Buenas alguien que conozca del tema, tengo dudas con lo que he encontrado en Google y en el foro acerca del SPWM para controlar un motor trifásico, pues bien mi duda es la siguiente es lo mismo el SPWM y el DDS ? y si lo que he encontrado acerca del DDS me sirve para hacer el inversor, o no tiene alguna relación con el inversor y si alguien a realizado o sabe acerca del control de un motor trifasico le agradeceria de antemano, gracias por su atención.

Link acerca del DDS: http://interface.khm.de/index.php/lab/interfaces-advanced/arduino-dds-sinewave-generator/

DDS de tres fases.

http://forum.arduino.cc/index.php?topic=121727.0

Para que hacer un inversor trifásico? A menos que sea una tarea del colegio/instituto o universidad no tiene sentido práctico ya que nunca igualarás un variador comercial.

En respuesta a tu pregunta: Si te sirve. DDS es Direct Digital Synthesys SPWM es lo mismo pero como rama específica del DDS.

Hola, exacto es un trabajo de universidad simplemente quiero un poco mas de referencia y si sabes que referencia de MOSFET se usan para este caso, gracias

Bueno si eres universatario se mas detallista al momento de explicarte, no tan ambiguo.

Especifica debidamente todo el proyecto. Si hablas de mosfet, no es lo mismo un mosfet 1A que otro de 100A ni uno con Vds 50V y otro con Vds 800V

Ya tienes el motor que vas a controlar. Sabes la tensión y la corriente nominal?

El proyecto consiste en elaborar un inversor trifásico microcontrolado.

La carga que se quiere controlar es un motor trifásico las especificaciones aparecen en la imagen el cual es un motor de 1/2 HP a 1680 RPM.

La idea es realizar el inversor tifásico para variar la frecuencia y hacer un control vectorial de las RPMS, no se si pueda implementar el mismo código que aparece en este link http://forum.arduino.cc/index.php?topic=323650.0 o si no como pódria adaptarlo a mi proyecto a una tension de linea de 220V, que tipo de MOSFET me recomendarias usar y que necesitaría como etapa de aislación de potencia para disparar los MOSFET o si lo puedo hacer directamente de los pines del Arduino UNO, como podria hacer los calculos para determinar la frecuencia que trabajara el inversor?.

Bueno podria responderte mucho de lo que preguntas pero como eres estudiante universitario voy a pedir que hagas un esfuerzo e investigues y no pidas todo servido.

Yo te iré preguntando y tu dame tu opinión (es tu trabajo no el mío):

Que elementos requieres para seleccionar el MOSFET? Tensión y corriente. Entonces? Que opinas?

Para la aislación te recomiendo este integrado IR2101 o el que lo este superando

|500x181 Este integrado es un driver para los MOSFET. Si quieres aislarlo puedes usar optos a la entrada. Las velocidades de conmutación que uses no complicarán en nada el comportamiento de la etapa de salida.

Si claro la idea es investigar, por cierto muchas gracias por tu tiempo. Bueno tienes razón con respecto a que MOSFET deba usar he encontrado que el IRFP460, pero por cuestiones de que lo pregunte en tiendas electrónicas y no lo consegui creo que puedo optar por el IRFP450, el cuál maneja una corriente de 14A y un VDS de 500V, ya que voy a rectificar y filtrar de la red trifasica, lo que aun no se es cuanta capacitancia debería poner en la etapa de filtrado, no creo que sea el calculo normal como si se tratase de una fuente.

Y con respecto al IR2101 me sirve para disparar los 6 MOSFET, y para un mayor aislamiento le pondria optooaisladores MCT6, pienso usar un Vgs de 15V que creo que se adaptaría bien, tampoco quiero todo en bandeja de plata solo quiero que me ayudes lo que mas pueda y que pena si aun soy un poco ambiguo hace mucho no participaba en un foro pero ahora me veo en la necesidad ya que es potencia y hay que tener mucho cuidado por eso quiero hacer los cálculos respectivos y gracias por la paciencia.

Por cierto este es otro código que he encontrado, podrías darme tu opinión si crees que aplique a mi proyecto:

/*
*
* DDS Sine Generator mit ATMEGS 328
* Timer2 generates the  31250 KHz Clock Interrupt
* Use Timer2 Interrupt to change duty cycle for the output PWM signals
* D. Tolken
* 120 degress out of phase signals for 3 phase BLDC motor controller
* CPUT, South Africa


a Huge thumbs up and thanks must be given to Martin Nawrath for the developement of the original code to generate a sine wave using PWM and a LPF.
Link:
                                         http://interface.khm.de/index.php/lab/experiments/arduino-dds-sinewave-generator/
*/

#include "avr/pgmspace.h" //Store data in flash (program) memory instead of SRAM

// 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 a bit to have the properties of a clear bit operator
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//define a bit to have the properties of a set bit operator

int PWM1= 11;// PWM1 output, phase 1
int PWM2 = 3; //[WM2 ouput, phase 2
int PWM3 = 10; //PWM3 output, phase 3
int offset_1 = 85; //offset 1 is 120 degrees out of phase with previous phase, Refer to PWM to sine.xls
int offset_2 = 170; //offset 2 is 120 degrees out of phase with offset 1. Refer to PWM to sine.xls
int program_exec_time = 6; //monitor how quickly the interrupt trigger
int ISR_exec_time = 7; //monitor how long the interrupt takes

double dfreq;
const double refclk=31376.6;      // measured output frequency

// variables used inside interrupt service declared as voilatile
volatile byte current_count;              // Keep track of where the current count is in sine 256 array
volatile byte ms4_delay;             //variable used to generate a 4ms delay
volatile byte c4ms;              // after every 4ms this variable is incremented, its used to create a delay of 1 second
volatile unsigned long phase_accumulator;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m, refer to DDS_calculator (from Martin Nawrath) for explination.

void setup()
{
  pinMode(PWM1, OUTPUT);      //sets the digital pin as output
  pinMode(PWM2, OUTPUT);      //sets the digital pin as output
  pinMode(PWM3, OUTPUT);      //sets the digital pin as output
  pinMode(program_exec_time, OUTPUT);      //sets the digital pin as output
  pinMode(9, OUTPUT);         //sets the digital pin as output
  sbi(PORTD,program_exec_time); //Sets the pin
  Setup_timer1();
  Setup_timer2();
  
  //Disable Timer 1 interrupt to avoid any timing delays
  cbi (TIMSK0,TOIE0);              //disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              //enable Timer2 Interrupt

  dfreq=1000.0;                    //initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  //calulate DDS new tuning word 

}
void loop()
{
  while(1) 
  {
      sbi(PORTD,program_exec_time); //Sets the pin 
      if (c4ms > 250) // c4ms = 4ms, thus 4ms *250 = 1 second delay
       {                 
        c4ms=0;                          //Reset c4ms
        dfreq=analogRead(0);             //Read voltage on analog 1 to see desired output frequency, 0V = 0Hz, 5V = 1.023kHz
        cbi (TIMSK2,TOIE2);              //Disable Timer2 Interrupt
        tword_m=pow(2,32)*dfreq/refclk;  //Calulate DDS new tuning word
        sbi (TIMSK2,TOIE2);              //Enable Timer2 Interrupt 
      }
  }
}

//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer1(void)
{
  // Timer1 Clock Prescaler to : 1
  sbi (TCCR1B, CS10);
  cbi (TCCR1B, CS11);
  cbi (TCCR1B, CS12);
  
  // Timer1 PWM Mode set to Phase Correct PWM
  cbi (TCCR1A, COM1A0);
  sbi (TCCR1A, COM1A1);
  cbi (TCCR1A, COM1B0); 
  sbi (TCCR1A, COM1B1);

  // Mode 1 / Phase Correct PWM
  sbi (TCCR1A, WGM10); 
  cbi (TCCR1A, WGM11);
  cbi (TCCR1B, WGM12);
  cbi (TCCR1B, WGM13);
}

//Timer 1 setup
//Set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz 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);
  cbi (TCCR2A, COM2B0); 
  sbi (TCCR2A, COM2B1);
  
  // Mode 1  / Phase Correct PWM
  sbi (TCCR2A, WGM20);  
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
}


//Timer2 Interrupt Service at 31372,550 KHz = 32uSec
//This is the timebase REFCLOCK for the DDS generator
//FOUT = (M (REFCLK)) / (2 exp 32)
//Runtime : 8 microseconds
ISR(TIMER2_OVF_vect)
{
  cbi(PORTD,program_exec_time); //Clear the pin
  sbi(PORTD,ISR_exec_time);          // Sets the pin

  phase_accumulator=phase_accumulator+tword_m; //Adds tuning M word to previoud phase accumulator. refer to DDS_calculator (from Martin Nawrath) for explination.
  current_count=phase_accumulator >> 24;     // use upper 8 bits of phase_accumulator as frequency information                      
  
  OCR2A=pgm_read_byte_near(sine256 + current_count); // read value fron ROM sine table and send to PWM
  OCR2B=pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_1)); // read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM1
  
  OCR1A = pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_2));// read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM2
  OCR1B = pgm_read_byte_near(sine256 + (uint8_t)(current_count + offset_2));// read value fron ROM sine table and send to PWM, 120 Degree out of phase of PWM2
  
  //increment variable ms4_delay every 4mS/125 =  milliseconds 32uS
  if(ms4_delay++ == 125) 
  {  
    c4ms++;
    ms4_delay=0; //reset count
   }   

cbi(PORTD,ISR_exec_time);            //Clear the pin
}

Datasheet IRFP450: http://www.datasheetcatalog.com/datasheets_pdf/I/R/F/P/IRFP450.shtml

Circuito de inversor trifasico:

Te recomiendo que investigues en International Rectifier y en Freescale. Ambos tienen amplia experiencia en el tema. Proveen muchos elementos que usa la industria. Asi que sus notas de aplicación siempre son referencia para mi en muchos proyectos.

Antes de opinera sobre los códigos debo buscar algo que tiene que ver con un problema que se presenta al conmutar los MOSFET que si no retardas el disparo termina quemándolos. No lo tengo muy presente pero si esta documentado entre mi bibilografía. Lo encuento y lo posteo.

Vale muchas gracias, y creo que hablas del tiempo muerto si no estoy mal, es el mismo tiempo de desfase?

Hola, he probado el siguiente código y lo he simulado en proteus, el archivo de proteus lo adjunto si puedes probar te lo agradeceria y también si me puedes dar tu opinión con respecto a la señal de salida que brinda el osciloscopio si es la correcta y si el circuito con los IR2101 y los MOSFETS estan trabajando como es, por ultimo añado que use 3 PWM y este dispara a los MOSFETS impares del puente inversor(Q1,Q3,Q5) y a los MOSFETS pares les aplique el complemento del PWM osea ~PWMX correspondiente a su numero impar(Q2,Q4,Q6) esto debido a que creo que no es posible trabajar con los 6 OCRn que posee el atmega entonces creo que asi anda bien, y lo determine leyendo este IEEE, http://www.laccei.org/LACCEI2013-Cancun/RefereedPapers/RP030.pdf El codigo que utilice fue el siguiente: ( ya que posee la caracteristica de poder variar la frecuencia de salida del DDS)

 #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  const char 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 =9; // 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(38400); // 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
}

Cualquier opinion,critica constructiva todo sirve gracias de antemano.

Archivo de proteus 8.1 :slight_smile:

Inversor_Arduino.zip (22.5 KB)

Hola! mi nombre es Gabri y es la primera vez que hablo en este foro. Estudie ingeniería de la energía (por lo que se lo justo de electronica). Tambien estoy iniciandome en arduino.

Estoy intentando diseñar un inversor para mi casa. Queremos hacer una instalación fotovoltaicas con baterias a 48 V y un inversor para sacarla a 220V.Y hablariamos de una potencia entorno a 6kW.
Vale, antes he leido que no merecia la pena por que no superaremos lo que hay en el mercado. ¿esto sigue siendo valido si lo que pretendo no es superarlo si no ahorrar costess? y aprender claro.

Bueno creo que lo más correcto es que cree un nuevo tema, aun asi os dejo aquí el codigo que he creado para fabricar la senoidal. Lo subo por si te sirve a ti y para que opineis y digas si puede funcionar o que. Tengo dudas sobre como de pequeño puedo hacer el paso de tiempo (‘p’)sin que se cuelgue el arduino. Tambien faltaría algo para añadir los tiempos muertos. Pero antes quiero saber si es valido para seguir trabajando en el o no. Lo que hago es comparar las ecuaciones triangular y senoidal.

PWM.2.ino (2.36 KB)

surbyte: Te recomiendo que investigues en International Rectifier y en Freescale. Ambos tienen amplia experiencia en el tema. Proveen muchos elementos que usa la industria. Asi que sus notas de aplicación siempre son referencia para mi en muchos proyectos.

Antes de opinera sobre los códigos debo buscar algo que tiene que ver con un problema que se presenta al conmutar los MOSFET que si no retardas el disparo termina quemándolos. No lo tengo muy presente pero si esta documentado entre mi bibilografía. Lo encuento y lo posteo.

gabrielC: Hola! mi nombre es Gabri y es la primera vez que hablo en este foro. Estudie ingeniería de la energía (por lo que se lo justo de electronica). Tambien estoy iniciandome en arduino.

Estoy intentando diseñar un inversor para mi casa. Queremos hacer una instalación fotovoltaicas con baterias a 48 V y un inversor para sacarla a 220V.Y hablariamos de una potencia entorno a 6kW. Vale, antes he leido que no merecia la pena por que no superaremos lo que hay en el mercado. ¿esto sigue siendo valido si lo que pretendo no es superarlo si no ahorrar costess? y aprender claro.

Bueno creo que lo más correcto es que cree un nuevo tema, aun asi os dejo aquí el codigo que he creado para fabricar la senoidal. Lo subo por si te sirve a ti y para que opineis y digas si puede funcionar o que. Tengo dudas sobre como de pequeño puedo hacer el paso de tiempo ('p')sin que se cuelgue el arduino. Tambien faltaría algo para añadir los tiempos muertos. Pero antes quiero saber si es valido para seguir trabajando en el o no. Lo que hago es comparar las ecuaciones triangular y senoidal.

Hola Gabri, yo tambien estoy aprendiendo veo que tienes razón en cuanto a los conocimientos a electrónica mas especificamente en lo que es el concepto del SPWM el cual yo no manejo muy bien pero, si manejo lo que es la programación y mas en Arduino que es donde he aprendido mas de un año, lo que te queria decir respecto a tu código al parecer esta bien, pero puedes mejorarlo, como?, facil ejecutar la funcion o operación del seno que posee el micro, le tardaria varios ciclos de reloj, lo que se hace es crear un vector o array con los valores de la funcion seno ya calculados y solo sea asignarlos, y como otra observacion si vas a poner en ON/OFF un pin haslo usando los registro, por lo mismo ya que la funcion digitalWrite le toma otros cuantos ciclos de reloj al Atmega328, o si no es que uses el PWM como tal, espero que te sirva de algo, buen dia.

PDTA: con respecto al vector con los valores, lo puedes hacer en una hoja de calculo de EXCEL.