// Automatically generated C++ file on Thu Apr 25 20:02:35 2024 // // To build with Digital Mars C++ Compiler: // // dmc -mn -WD pwm_modulation.cpp kernel32.lib ////////////////////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include // Constant declaration //#define TRUNC_METHOD #define pi 3.14159265358979323846 #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 #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 // Functions double max3(double a, double b,double c); double min3(double a, double b,double c); double modePWM(double t, double T); ////////////////////////////////////////////////////////////////////////////////////////////////////// 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 https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain for more information. int __stdcall DllMain(void *module, unsigned int reason, void *reserved) { return 1; } void display(const char *fmt, ...) { // for diagnostic print statements msleep(30); fflush(stdout); va_list args = { 0 }; va_start(args, fmt); vprintf(fmt, args); va_end(args); fflush(stdout); msleep(30); } void bzero(void *ptr, unsigned int count) { unsigned char *first = (unsigned char *) ptr; unsigned char *last = first + count; while(first < last) *first++ = '\0'; } // #undef pin names lest they collide with names in any header file(s) you might include. #undef dbg1 #undef dbg2 #undef dbg3 #undef PWM_AH #undef PWM_AL #undef PWM_BH #undef PWM_BL #undef PWM_CH #undef PWM_CL // user-defined data - within struct struct sPWM_MODULATION { // declare the structure here double maxstep; // max timestep definition double tPrev; double fallCount, riseCount; // tried to implement a counter double tRise, tFall; }; // main function for algorithms extern "C" __declspec(dllexport) void pwm_modulation(struct sPWM_MODULATION **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 F_SW = data[ 3].d; // input parameter double &dbg1 = data[4].d; // output double &dbg2 = data[5].d; // output double &dbg3 = data[6].d; // output double &PWM_AH = data[7].d; // output double &PWM_AL = data[8].d; // output double &PWM_BH = data[9].d; // output double &PWM_BL = data[10].d; // output double &PWM_CH = data[11].d; // output double &PWM_CL = data[12].d; // output // variable declaration const double clk = 100e6; const double peak = 10; // steps = peak / clk = 100ns const double step = peak/clk; double carrier; double Fsw = 8e3; // F_SW; re-add later, use for debugging for now double m = 1; //MOD; // re-add later, use for debugging for now double Fm = 100; // Fo; // re-add later, use for debugging for now double Tsw = 1 / Fsw; double w = 2*pi*Fm; double tDead = 50*step; if(!*opaque) // executed only once during startup { *opaque = (struct sPWM_MODULATION *) malloc(sizeof(struct sPWM_MODULATION)); bzero(*opaque, sizeof(struct sPWM_MODULATION)); struct sPWM_MODULATION *inst = *opaque; inst->maxstep = step; } struct sPWM_MODULATION *inst = *opaque; // Implement module evaluation code here: // carrier signal carrier = modePWM(t, Tsw); // control signals double vref_A = m*sin(w*t + phase); double vref_B = m*sin(w*t - (2*pi)/3 + phase); double vref_C = m*sin(w*t + (2*pi)/3 + phase); // common-mode offset 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-2*PWM_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; // state logic bool pwm_a = 0; bool pwm_a_del = 0; if (inst->tPrev==0) inst->tPrev=1e308; // pwm logic checks - create pwm logic w/o dead-time then add delays if ( (mod_A >= carrier) ) { pwm_a = 1; inst->tFall = t; // the moment mod_A and carrier cross on falling edge increase fallings edge count inst->fallCount++; } else if ( (mod_A <= carrier) ) { pwm_a = 0; inst->tRise = t; // the moment mod_A and carrier cross on rising edge increase rising edge count inst->riseCount++; } if ( (t == inst->tFall ) ) { inst->riseCount = 0; } if (t == inst->tRise) { inst->fallCount = 0; } if ( t >= inst->tRise + 2*tDead) { pwm_a_del = 0; } else if ( t >= inst->tFall - tDead) { pwm_a_del = 1; } // plotting dbg1 = carrier; dbg2 = mod_A; PWM_AH = pwm_a; PWM_AL = pwm_a_del; PWM_BH = inst->tFall; PWM_BL = inst->tRise; } extern "C" __declspec(dllexport) double MaxExtStepSize(struct sPWM_MODULATION *inst) { return inst->maxstep; // implement max timestep } // this function is called to read for next timestep extern "C" __declspec(dllexport) void Trunc(struct sPWM_MODULATION *inst, double t, union uData *data, double *timestep) { // limit the timestep to a tolerance if the circuit causes a change in struct sPWM_MODULATION const double ttol = 10e-9; if(*timestep > ttol) { double &dbg1 = data[4].d; // output double &dbg2 = data[5].d; // output double &dbg3 = data[6].d; // output double &PWM_AH = data[7].d; // output double &PWM_AL = data[8].d; // output double &PWM_BH = data[9].d; // output double &PWM_BL = data[10].d; // output double &PWM_CH = data[11].d; // output double &PWM_CL = data[12].d; // output // Save output vector const double _dbg1 = dbg1 ; const double _dbg2 = dbg2 ; const double _dbg3 = dbg3 ; const double _PWM_AH = PWM_AH; const double _PWM_AL = PWM_AL; const double _PWM_BH = PWM_BH; const double _PWM_BL = PWM_BL; const double _PWM_CH = PWM_CH; const double _PWM_CL = PWM_CL; struct sPWM_MODULATION tmp = *inst; pwm_modulation(&(&tmp), t, data); //if(tmp != *inst) // implement a meaningful way to detect if the state has changed //*timestep = ttol; // // Trunc() to reduce timestep to TTOL if OUT changes its status // if (tmp.last_pwm_a != inst->last_pwm_a) // *timestep = ttol; // // Trunc() to reduce timestep to TTOL if DelayOut changes its status // if (tmp.last_pwm_a_delay != inst->last_pwm_a_delay) // *timestep = ttol; // Restore output vector dbg1 = _dbg1 ; dbg2 = _dbg2 ; dbg3 = _dbg3 ; PWM_AH = _PWM_AH; PWM_AL = _PWM_AL; PWM_BH = _PWM_BH; PWM_BL = _PWM_BL; PWM_CH = _PWM_CH; PWM_CL = _PWM_CL; } } extern "C" __declspec(dllexport) void Destroy(struct sPWM_MODULATION *inst) { free(inst); } ////////////////////////////////////////////////////////////////////////////////////////////////// // Function prototypes 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) // generate 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; }