@@ -545,6 +545,7 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) {
545
545
break ;
546
546
547
547
case FOCModulationType::SinePWM :
548
+ case FOCModulationType::SpaceVectorPWM :
548
549
// Sinusoidal PWM modulation
549
550
// Inverse Park + Clarke transformation
550
551
_sincos (angle_el, &_sa, &_ca);
@@ -553,107 +554,32 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) {
553
554
Ualpha = _ca * Ud - _sa * Uq; // -sin(angle) * Uq;
554
555
Ubeta = _sa * Ud + _ca * Uq; // cos(angle) * Uq;
555
556
556
- // center = modulation_centered ? (driver->voltage_limit)/2 : Uq;
557
- center = driver->voltage_limit /2 ;
558
557
// 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
+ }
562
569
563
570
if (!modulation_centered) {
564
571
float Umin = min (Ua, min (Ub, Uc));
565
572
Ua -= Umin;
566
573
Ub -= Umin;
567
574
Uc -= Umin;
575
+ }else {
576
+ Ua += center;
577
+ Ub += center;
578
+ Uc += center;
568
579
}
569
580
570
581
break ;
571
582
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
-
657
583
}
658
584
659
585
// set the voltages in driver
0 commit comments