@@ -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