Please Help, Making SVPMW 5KHZ

Good afternoon. I am implementing an SVPWM in arduino uno with a switching frequency of 5000 Hz.

The code seems to be functional, except for the output frequency: it should be 5000 Hz, but the measured signal is only 50 Hz.

The code is provided below. I first designed the SVPWM in PLECS and then translated the blocks into code, except for the triangle wave generator, which was provided by ChatGPT :

double Vdc = 26;
double Ts = 0.0002;
double Frads = 50; 
double Amp = 1;
unsigned long clock_us = 0;
float t ;
double Sine1, Sine2, Sine3;
double Valfa, Vbeta, Angle, AngleRads, Vref;

double presec1, presec2, presec3, presec4, presec5, presec6, Sector, Mts, T11, T22, T1, T2 ,T0, T1T2T0, T1T0, T2T0;

double sin1, sin2 ,sin3;

double output1, output2, output3;


const float TRI_MAX = 1.066618e-2;
const float TRI_MIN = 0.933382e-2; 
const float TRI_FREQ = 5000.0;

float tri = TRI_MIN;
float step;
bool rising = true;

unsigned long lastUpdate = 0;
const int N = 100;

const int pin1 = 3;
const int pin2 = 5;
const int pin3 = 6;



void setup() {
           
pinMode(pin1, OUTPUT);
pinMode(pin2, OUTPUT);
pinMode(pin3, OUTPUT);        
  step = (TRI_MAX - TRI_MIN) / (N / 2);


}

void loop() {
  // Onda Triangular
  unsigned long now = micros();
  unsigned long Ts1 = 1000000UL / (TRI_FREQ * N);
  
    if (now - lastUpdate >= Ts1) {
    lastUpdate = now;
    
      if (rising) 
      {
      tri += step;
        if (tri >= TRI_MAX) 
        {
        tri = TRI_MAX;
        rising = false;
        }
      } else 
      {
        tri -= step;
          if (tri <= TRI_MIN) 
          {
          tri = TRI_MIN;
          rising = true;
          }
      }
      }

  // End Onda Triangular
  t = now / 1000000.0;
  

  
 

  Sine1= Amp*sin(2*PI*Frads*(t));
  Sine2= Amp*sin(2*PI*Frads*(t)-(2*PI/3));
  Sine3= Amp*sin(2*PI*Frads*(t)-(4*PI/3));
  Valfa = (Sine1 - Sine2 * 0.5 - Sine3 * 0.5) * (2.0 / 3.0);
  Vbeta = (Sine2 * (sqrt(3.0) / 2.0) - Sine3 * (sqrt(3.0) / 2.0)) * (-2.0 / 3.0);
  Angle = atan2(Vbeta, Valfa);
  AngleRads = Angle*(180/PI);
  Vref = sqrt(Valfa * Valfa + Vbeta * Vbeta);


  // Sector detection
  if(AngleRads>0 && AngleRads <= 60){
    presec1 = 1;
  }else{presec1 = 0;}

   if(AngleRads>60 && AngleRads <= 120){
    presec2 = 2;
  }else{presec2 = 0;}

   if(AngleRads>120 && AngleRads <= 180){
    presec3 = 3;
  }else{presec3 = 0;}

   if(AngleRads>-180 && AngleRads <= -120){
    presec4 = 4;
  }else{presec4 = 0;}
  
  if(AngleRads>-120 && AngleRads <= -60){
    presec5 = 5;
  }else{presec5 = 0;}

  if(AngleRads>-60 && AngleRads <= 0){
    presec6 = 6;
  
  }else{presec6 = 0;}

  Sector = presec1 + presec2 + presec3 + presec4 + presec5 + presec6;

 //times
  Mts= sqrt(3) * Vref * Ts/Vdc;
  T1 = (Mts * sin(Sector * PI/3 - Angle))*100;
  T2 = (Mts * sin(-(Sector-1) * PI/3 + Angle))*100;
  
  T11 = Mts * sin(Sector * PI/3 - Angle);
  T22 = Mts * sin(-(Sector-1) * PI/3 + Angle);
  T0 = ((-T11 - T22 + Ts)/2)*100;
  
  T1T2T0 = T1+T2+T0;
  T1T0 = T1+T0;
  T2T0 = T2+T0;

  switch((int)Sector) {
    case 1:
    case 6:
      sin1 = T1T2T0;
      break;

    case 2:
      sin1 = T1T0;
      break;

    case 5:
      sin1 = T2T0;
      break;

    case 3:
    case 4:
      sin1 = T0;
      break;

    default:
      sin1 = 0; // segurança
      break;
  }

  switch((int)Sector) {
    case 2:
    case 3:
      sin2 = T1T2T0;
      break;

    case 4:
      sin2 = T1T0;
      break;

    case 1:
      sin2 = T2T0;
      break;

    case 5:
    case 6:
      sin2 = T0;
      break;

    default:
      sin2 = 0; // segurança
      break;
  }


  switch((int)Sector) {
    case 4:
    case 5:
      sin3 = T1T2T0;
      break;

    case 6:
      sin3 = T1T0;
      break;

    case 3:
      sin3 = T2T0;
      break;

    case 1:
    case 2:
      sin3 = T0;
      break;

    default:
      sin3 = 0; // segurança
      break;
  }


  //PULSE
  if (sin1 > tri) {
    digitalWrite(pin1, HIGH);
  } else {
    digitalWrite(pin1, LOW);
  }

  if (sin2 > tri) {
    digitalWrite(pin2, HIGH);
  } else {
    digitalWrite(pin2, LOW);
  }

  if (sin3 > tri) {
    digitalWrite(pin3, HIGH);
  } else {
    digitalWrite(pin3, LOW);
  }
  
  
  }

What is the full name for SVPWM?

And what exactly, is that?

A 5KHz signal has a period of 200uSec.

Here's just one fragment of floating point math your sketch is doing.

Just this fragment takes 720uSec to execute on an Uno R3. This one fragment takes almost 4x the desired period of your output signal.

And you wonder why it doesn't work the way you want?

Space Vector Pulse Width Modulation

This is my first Arduino program, which I'm developing for my dissertation.

If it's as you say, @van_der_decken, would switching to a more powerful Arduino board solve the issue?

Can you present the trigonometric functions for your SVPWM?

As far I understand, it can be solved with replacing calculations by table values.

I have generated three phase PWM signals using ESP32S3 timers

e.g. 1KHz 50%PWM

1KHz 80% PWM

1KHz 20% PWM

also look at ESP32S3 Remote Control Transceiver (RMT) module

I tried that first, but for 5kHz there are too many variables involved the program did not acept it. I can't lower the frequency; it has to be 5kHz.

The number of variables are not depended on frequency at all. You need to generate a table for a single period only.

There are projects in the Net for generating a three-phase signal on a UNO, although it's quite complicated. However, the problem isn't the number of variables, but the small number of hardware timers.

If? Okay, you're on your own.

im using gemine to translate sorry.
This one did not use the gemine to translate.

I am from portugal.

Also using a digitalWrite() is not a good way to execute time-critical sections of code.

If you want to write fast code, you need to learn how to use the microcontroller's hardware capabilities—direct writing to GPIO registers, working with hardware timers, and DMA.

If I were you, I'd choose a Rasberry Pico 2040/2350 microcontroller, create a sine wave point table for all three channels, and use a PIO machine with DMA data loading for pin output.

if your just toggling 3 pins in 3 phases

// 3-phase generator

const byte Nphase = 3;
const byte Pins []  = { 10, 11, 12 };

byte index [Nphase];

const unsigned Nsamp = 2 *Nphase;
int table [Nsamp];

const unsigned long Freq       = 5000L;
const unsigned long UsecPeriod = 1000000L / (Nsamp *Freq);
      unsigned long usec0;

unsigned long msec0;
unsigned long cnt;
char s [90];

// -----------------------------------------------------------------------------
void loop()
{
    unsigned long usec = micros ();
    if (usec - usec0 < UsecPeriod)
        return;

    usec0 += UsecPeriod;

    for (byte i = 0; i < Nphase; i++)  {
        digitalWrite (Pins [i], table [index [i]]);

        if (Nsamp < ++index [i])
            index [i] -= Nsamp;
    }

    if (! (++cnt % 1000))  {
        unsigned long msec = millis ();
        sprintf (s, " %9lu", msec - msec0);
        Serial.println (s);
        msec0 = msec;
    }
}

// -----------------------------------------------------------------------------
void setup()
{
    Serial.begin (9600);

    for (unsigned n = 0; n < Nphase; n++)
        pinMode (Pins [n], OUTPUT);

    for (unsigned n = 0; n < Nsamp/2; n++)
        table [n] = 1;

    index [0] = 0;
    index [1] = Nsamp /3;
    index [2] = Nsamp *2/3;

    sprintf (s, " %lu usecPeriod", UsecPeriod);
    Serial.println (s);
}

Do you tink that rasberry can take 4 table it each 201variable?

Exemple:
int SVPWM_time1[201]={51, 95, 111, 84, 122, 73, 133, 62, 143, 52, 154, 41, 164, 31, 174, 21, 183, 13, 189, 10, 191, 7, 194, 5, 196, 3, 197, 2, 199, 1, 199, 0, 200, 0, 200, 0, 200, 1, 199, 2, 198, 3, 196, 5, 194, 7, 192, 9, 190, 12, 188, 12, 190, 9, 192, 7, 194, 5, 196, 3, 198, 2, 199, 1, 200, 0, 200, 0, 200, 0, 199, 1, 199, 2, 197, 3, 196, 5, 194, 7, 191, 10, 189, 13, 183, 21, 174, 31, 164, 41, 154, 52, 143, 62, 133, 73, 122, 84, 111, 95, 100, 106, 89, 116, 78, 127, 68, 138, 57, 148, 47, 159, 36, 169, 26, 179, 17, 186, 11, 190, 9, 193, 6, 195, 4, 197, 3, 198, 1, 199, 1, 200, 0, 200, 0, 200, 0, 199, 1, 198, 2, 197, 4, 195, 6, 193, 8, 191, 10, 188, 13, 188, 10, 191, 8, 193, 6, 195, 4, 197, 2, 198, 1, 199, 0, 200, 0, 200, 0, 200, 1, 199, 1, 198, 3, 197, 4, 195, 6, 193, 9, 190, 11, 186, 17, 179, 26, 169, 36, 159, 47, 148, 57, 138, 68, 127, 78, 116, 89, 106, 49};

i think it has plenty of memory, but because it an an OS running, is a raspberry pi fast enough for real-time processing?

curious, why 4 tables and why 201 values?

i follow this tutorial but used my svpwm wave:https://www.youtube.com/watch?v=Xw8c71GXv78&t=83s.

Is 3 tables for the times the others(the nots) are made analog it dead times.
the other 1 is if is need one for high and lows.

The 201 is the times for the 5khz if, i has making 50hz woud be 20 like the video.

i would have thought you could get by with fewer samples at high frequencies

Why do you doubt this? A table of 200 values ​​is very small; the RP2040's memory is sufficient for hundreds of such tables.
Furthermore, since your table contains constants, it can be loaded into program memory, and then these tables can be loaded even in Uno

Do not confuse Raspberry Pi with Raspberry Pico. The later is an Arduino compatible microcontroller

we have three sandarda Arduino boards:
Arduino UNO
Arduino NNAO
Arduino MEGA

Are you referring to which one of the above?