Skip to content

Commit 1694fa3

Browse files
Merge pull request #309 from Candas1/SVPWM_midpoint
SVPWM with midpoint clamp
2 parents e9896ee + 6cbbf03 commit 1694fa3

File tree

1 file changed

+16
-90
lines changed

1 file changed

+16
-90
lines changed

src/BLDCMotor.cpp

Lines changed: 16 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) {
545545
break;
546546

547547
case FOCModulationType::SinePWM :
548+
case FOCModulationType::SpaceVectorPWM :
548549
// Sinusoidal PWM modulation
549550
// Inverse Park + Clarke transformation
550551
_sincos(angle_el, &_sa, &_ca);
@@ -553,107 +554,32 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) {
553554
Ualpha = _ca * Ud - _sa * Uq; // -sin(angle) * Uq;
554555
Ubeta = _sa * Ud + _ca * Uq; // cos(angle) * Uq;
555556

556-
// center = modulation_centered ? (driver->voltage_limit)/2 : Uq;
557-
center = driver->voltage_limit/2;
558557
// Clarke transform
559-
Ua = Ualpha + center;
560-
Ub = -0.5f * Ualpha + _SQRT3_2 * Ubeta + center;
561-
Uc = -0.5f * Ualpha - _SQRT3_2 * Ubeta + center;
558+
Ua = Ualpha;
559+
Ub = -0.5f * Ualpha + _SQRT3_2 * Ubeta;
560+
Uc = -0.5f * Ualpha - _SQRT3_2 * Ubeta;
561+
562+
center = driver->voltage_limit/2;
563+
if (foc_modulation == FOCModulationType::SpaceVectorPWM){
564+
// Midpoint Clamp
565+
float Umin = min(Ua, min(Ub, Uc));
566+
float Umax = max(Ua, max(Ub, Uc));
567+
center -= (Umax+Umin) / 2;
568+
}
562569

563570
if (!modulation_centered) {
564571
float Umin = min(Ua, min(Ub, Uc));
565572
Ua -= Umin;
566573
Ub -= Umin;
567574
Uc -= Umin;
575+
}else{
576+
Ua += center;
577+
Ub += center;
578+
Uc += center;
568579
}
569580

570581
break;
571582

572-
case FOCModulationType::SpaceVectorPWM :
573-
// Nice video explaining the SpaceVectorModulation (SVPWM) algorithm
574-
// https://www.youtube.com/watch?v=QMSWUMEAejg
575-
576-
// the algorithm goes
577-
// 1) Ualpha, Ubeta
578-
// 2) Uout = sqrt(Ualpha^2 + Ubeta^2)
579-
// 3) angle_el = atan2(Ubeta, Ualpha)
580-
//
581-
// equivalent to 2) because the magnitude does not change is:
582-
// Uout = sqrt(Ud^2 + Uq^2)
583-
// equivalent to 3) is
584-
// angle_el = angle_el + atan2(Uq,Ud)
585-
586-
float Uout;
587-
// a bit of optitmisation
588-
if(Ud){ // only if Ud and Uq set
589-
// _sqrt is an approx of sqrt (3-4% error)
590-
Uout = _sqrt(Ud*Ud + Uq*Uq) / driver->voltage_limit;
591-
// angle normalisation in between 0 and 2pi
592-
// only necessary if using _sin and _cos - approximation functions
593-
angle_el = _normalizeAngle(angle_el + atan2(Uq, Ud));
594-
}else{// only Uq available - no need for atan2 and sqrt
595-
Uout = Uq / driver->voltage_limit;
596-
// angle normalisation in between 0 and 2pi
597-
// only necessary if using _sin and _cos - approximation functions
598-
angle_el = _normalizeAngle(angle_el + _PI_2);
599-
}
600-
// find the sector we are in currently
601-
sector = floor(angle_el / _PI_3) + 1;
602-
// calculate the duty cycles
603-
float T1 = _SQRT3*_sin(sector*_PI_3 - angle_el) * Uout;
604-
float T2 = _SQRT3*_sin(angle_el - (sector-1.0f)*_PI_3) * Uout;
605-
// two versions possible
606-
float T0 = 0; // pulled to 0 - better for low power supply voltage
607-
if (modulation_centered) {
608-
T0 = 1 - T1 - T2; // modulation_centered around driver->voltage_limit/2
609-
}
610-
611-
// calculate the duty cycles(times)
612-
float Ta,Tb,Tc;
613-
switch(sector){
614-
case 1:
615-
Ta = T1 + T2 + T0/2;
616-
Tb = T2 + T0/2;
617-
Tc = T0/2;
618-
break;
619-
case 2:
620-
Ta = T1 + T0/2;
621-
Tb = T1 + T2 + T0/2;
622-
Tc = T0/2;
623-
break;
624-
case 3:
625-
Ta = T0/2;
626-
Tb = T1 + T2 + T0/2;
627-
Tc = T2 + T0/2;
628-
break;
629-
case 4:
630-
Ta = T0/2;
631-
Tb = T1+ T0/2;
632-
Tc = T1 + T2 + T0/2;
633-
break;
634-
case 5:
635-
Ta = T2 + T0/2;
636-
Tb = T0/2;
637-
Tc = T1 + T2 + T0/2;
638-
break;
639-
case 6:
640-
Ta = T1 + T2 + T0/2;
641-
Tb = T0/2;
642-
Tc = T1 + T0/2;
643-
break;
644-
default:
645-
// possible error state
646-
Ta = 0;
647-
Tb = 0;
648-
Tc = 0;
649-
}
650-
651-
// calculate the phase voltages and center
652-
Ua = Ta*driver->voltage_limit;
653-
Ub = Tb*driver->voltage_limit;
654-
Uc = Tc*driver->voltage_limit;
655-
break;
656-
657583
}
658584

659585
// set the voltages in driver

0 commit comments

Comments
 (0)