From 2f9e96708795b22fa8e47cc2cc5b3a85bdbae093 Mon Sep 17 00:00:00 2001 From: stijncarelsbergh Date: Thu, 8 Oct 2026 00:04:32 +0200 Subject: [PATCH] fix(trapezoid commutation): non-centred modulation produced no output for Uq < 0 The trapezoid branches used `center = Uq` for non-centred modulation, which works for Uq > 0 but makes all three phase voltages <= 0 for Uq < 0; setPwm() clamps them to 0, so the motor gets no voltage at all in one direction. The sine/SVPWM branches handle this by shifting the phases up by their minimum, which is what non-centred modulation means for every mode. Using the same min-clamp for the trapezoid modes is exactly equivalent for Uq > 0 (every sector map contains a -1, so min = -Uq and the result is map*Uq + Uq as before) and gives the correct shifted waveform for Uq < 0. --- src/BLDCMotor.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/BLDCMotor.cpp b/src/BLDCMotor.cpp index 5f552f98a..1a4d3c12a 100644 --- a/src/BLDCMotor.cpp +++ b/src/BLDCMotor.cpp @@ -165,7 +165,7 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) { // centering the voltages around either // modulation_centered == true > driver.voltage_limit/2 // modulation_centered == false > or Adaptable centering, all phases drawn to 0 when Uq=0 - center = modulation_centered ? (driver->voltage_limit)/2 : Uq; + center = modulation_centered ? (driver->voltage_limit)/2 : 0; if(trap_120_map[sector][0] == _HIGH_IMPEDANCE){ Ua= center; @@ -184,6 +184,15 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) { driver->setPhaseState(PhaseState::PHASE_ON, PhaseState::PHASE_ON, PhaseState::PHASE_OFF);// disable phase if possible } + if(!modulation_centered){ + // non-centered modulation: shift all phases up so the lowest one is at 0, + // same idiom as the sine/SVPWM branches + float Umin = min(Ua, min(Ub, Uc)); + Ua -= Umin; + Ub -= Umin; + Uc -= Umin; + } + break; case FOCModulationType::Trapezoid_150 : @@ -193,7 +202,7 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) { // centering the voltages around either // modulation_centered == true > driver.voltage_limit/2 // modulation_centered == false > or Adaptable centering, all phases drawn to 0 when Uq=0 - center = modulation_centered ? (driver->voltage_limit)/2 : Uq; + center = modulation_centered ? (driver->voltage_limit)/2 : 0; if(trap_150_map[sector][0] == _HIGH_IMPEDANCE){ Ua= center; @@ -217,6 +226,15 @@ void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) { driver->setPhaseState(PhaseState::PHASE_ON, PhaseState::PHASE_ON, PhaseState::PHASE_ON); // enable all phases } + if(!modulation_centered){ + // non-centered modulation: shift all phases up so the lowest one is at 0, + // same idiom as the sine/SVPWM branches + float Umin = min(Ua, min(Ub, Uc)); + Ua -= Umin; + Ub -= Umin; + Uc -= Umin; + } + break; case FOCModulationType::SinePWM :