Hi all,
I need some help writing C++ code to generate the PWM timings for a SVPWM modulation technique. I am posting only the PWM generation block. I am struggling to add dead-time to my code; I don’t quite understand how to extract the current time and delay (if that makes sense). I am able to generate this part of the simulation using LOGIC gates to produce the delay, but I would like to do it in code. I have also posted some waveforms to illustrate that the logic behind the modulation signals and the carrier are correct, for anyone that is interested in using this later on.
The final aim is to create a steady-state simulation with an RL load that simulates a motor at a particular operating point. I have achieved this using a more analog approach which is a bit messy.
I can’t attach the simulation as I’m a new member (apparently). I have posted the code below. Once I am able to attach files, I will gladly do so and engage further with anyone that has an interest to produce a more accurate model.
CODE:
// Automatically generated C++ file on Fri Apr 19 22:27:30 2024
//
// To build with Digital Mars C++ Compiler:
//
// dmc -mn -WD pwm_modulation.cpp kernel32.lib
// Library includes - START
#include <stdio.h>
#include <math.h>
#include
#include
// Library includes - END
union uData
{
bool b;
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
float f;
double d;
long long int i64;
unsigned long long int ui64;
char *str;
unsigned char *bytes;
};
// int DllMain() must exist and return 1 for a process to load the .DLL
// See DllMain entry point (Process.h) - Win32 apps | Microsoft Learn for more information.
int __stdcall DllMain(void *module, unsigned int reason, void *reserved) { return 1; }
// #undef pin names lest they collide with names in any header file(s) you might include.
#undef CTRL_A
#undef CTRL_B
#undef CTRL_C
#undef MAX_ABC
#undef MIN_ABC
#undef CM_OFFSET
#undef MOD_A
#undef MOD_B
#undef MOD_C
#undef PWM_A
#undef PWM_B
#undef PWM_C
#undef PWM_AH
#undef PWM_AL
#undef PWM_BH
#undef PWM_BL
#undef PWM_CH
#undef PWM_CL
// Self-defined constants - START
#define pi 3.14159265358979323846
#define freqClk 72000000
#define clkPrescaler 63
#define PWM_MODE 2 // 0= edge-aligned; 1= centre-aligned uni-polar; 2= centre-aligned bi-polar
#define PWM_TYPE 0.5 // 0=DPWM 180; 0.5=SVPWM; 1.0=DPWM 0
#define t_dead 10e-6
#if (PWM_MODE == 0)
int mode = 0; // edge-aligned
#elif (PWM_MODE == 1)
int mode = 1; // centre-aligned uni-polar
#elif (PWM_MODE == 2)
int mode = 2; // centre-aligned bi-polar
#endif
// Self-defined constants - END
// FUNCTIONS - START
double max3(double a, double b,double c)
{
double result=0;
if (a > b && a > c)
{
result=a;
}
else if (b > a && b > c)
{
result=b;
}
else
{
result=c;
}
return result;
}
double min3(double a, double b,double c)
{
double result=0;
if (a < b && a < c)
{
result=a;
}
else if (b < a && b < c)
{
result=b;
}
else
{
result=c;
}
return result;
}
double modePWM(double t, double T) // generater carrier wave
{
if (mode == 0)
{
double Tsw = T;
return t/Tsw - floor(t/Tsw);
}
else if (mode == 1)
{
double Tsw = 2*T;
double Tnorm = fmod(t, Tsw);
double m = 2.0 / Tsw; // slope
if (Tnorm < Tsw/2) // rising
{
return m * Tnorm;
}
else // falling
{
return 1.0 - m * (Tnorm - Tsw/2);
}
}
else if (mode == 2)
{
double Tsw = 2*T;
double Tnorm = fmod(t, Tsw);
double m = 2.0 / Tsw;
if (Tnorm < Tsw / 2)
{
return 2 * m * Tnorm - 1.0;
}
else
{
return 1.0 - 2 * m * (Tnorm - Tsw / 2);
}
}
return 0;
}
// Define a struct to hold the PWM result - FOR FUTURE USE
struct PWMResult
{
bool pwm_H;
bool pwm_L;
};
PWMResult pwm(double duty, double deadTime, double carrier)
{
PWMResult result;
if ( (1 - duty - deadTime) > carrier)
{
result.pwm_H = false;
result.pwm_L = true;
}
else if ( (1 - duty + deadTime) > carrier )
{
result.pwm_H = false;
result.pwm_L = false;
}
else
{
result.pwm_H = true;
result.pwm_L = false;
}
return result;
}
// FUNCTIONS - END
extern “C” __declspec(dllexport) void pwm_modulation(void **opaque, double t, union uData *data)
{
double Fo = data[ 0].d; // input parameter
double phase = data[ 1].d; // input parameter
double MOD = data[ 2].d; // input parameter
double PWM_SELECT = data[ 3].d; // input parameter
double F_SW = data[ 4].d; // input parameter
double &CTRL_A = data[5].d; // output
double &CTRL_B = data[6].d; // output
double &CTRL_C = data[7].d; // output
double &MAX_ABC = data[8].d; // output
double &MIN_ABC = data[9].d; // output
double &CM_OFFSET = data[10].d; // output
double &MOD_A = data[11].d; // output
double &MOD_B = data[12].d; // output
double &MOD_C = data[13].d; // output
double &PWM_A = data[14].d; // output
double &PWM_B = data[15].d; // output
double &PWM_C = data[16].d; // output
double &PWM_AH = data[17].d; // output
double &PWM_AL = data[18].d; // output
double &PWM_BH = data[19].d; // output
double &PWM_BL = data[20].d; // output
double &PWM_CH = data[21].d; // output
double &PWM_CL = data[22].d; // output
// Implement module evaluation code here:
// General variable declaration
double W = 2piFo;
double Tsw = 1/F_SW;
// Control signals
double vref_A = MODsin(Wt + phase);
double vref_B = MODsin(Wt - (2pi)/3 + phase);
double vref_C = MODsin(Wt + (2pi)/3 + phase);
// Common-mode offset generation
double max_abc = max3(vref_A, vref_B, vref_C);
double min_abc = min3(vref_A, vref_B, vref_C);
double cm_offset = ((PWM_TYPE*max_abc + (1-PWM_TYPE)min_abc + (1-2PWM_TYPE)*0.5));
// Modulation signals
double mod_A = vref_A - cm_offset;
double mod_B = vref_B - cm_offset;
double mod_C = vref_C - cm_offset;
// PWM output setting
if ( mod_A > modePWM(t, Tsw) )
{
PWM_AH = true;
PWM_AL = false;
}
else if ( mod_A < modePWM(t, Tsw) )
{
PWM_AH = false;
PWM_AL = true;
}
// plotting for debugging
CTRL_A = vref_A; //
MAX_ABC = max_abc;
MIN_ABC = min_abc;
CM_OFFSET = cm_offset;
MOD_A = mod_A;
}
CODE END
** Excuse my poor code, I’m not very good at it **