SVPWM算法公式推导:从几何原理到代码实现
SVPWM算法公式推导:从几何原理到代码实现
在磁场定向控制(FOC)中,空间矢量脉宽调制(SVPWM)负责将二维的电压参考矢量
1. 符号定义与前提
: 目标电压空间矢量,位于 静止坐标系。 : 的幅值,即 。 : 在 坐标系中的角度(电角度)。 : 直流母线电压。 : PWM周期(载波周期)。 : 两个相邻有效矢量 和 在一个 内需要作用的时间。它们对应于代码中的T1和T2。 : 零矢量( 或 )的作用时间, 。
前提:采用 Clarke等幅值变换。这意味着变换前后电压矢量的幅值(模长)物理意义保持不变,即相电压峰值与
其中
2. 基于伏秒平衡与正弦定理的原始公式推导
根据SVPWM原理,在一个PWM周期
考虑

对该三角形应用 正弦定理:
定义
定义
通过逆变电路的导通状态和三相绕组的连接情况可知,六个基本矢量的幅值均为
同时可知
代入上式可得:
同理:
同时:
电压归一化与六边形内切圆半径

SVPWM的线性调制区(即能合成圆形旋转磁场而不畸变的区域)由六个有效矢量构成的正六边形的 内切圆 所限定。
该内切圆的半径
观察下面两个表达式
可以发现分母完全相同, 这意味着如果进行 电压归一化,将电压矢量幅值
记这个归一化电压为
这就是最终得到的简洁形式。在实际实现中,我们以直流母线电压 power_supply,则:
在FOC控制中,我们主要关注q轴电压
float T1 = self->Uq / self->power_supply * _sin(M_PI_3 - alpha);
float T2 = self->Uq / self->power_supply * _sin(alpha);
float T0 = 1 - T1 - T2;self->Uq / self->power_supply:归一化电压比例,对应理论公式中的M_PI_3: 的弧度值( )alpha:当前扇区内角度_sin():正弦函数实现
扇区分配与PWM占空比计算
计算出相邻两个有效矢量的作用时间
以扇区0(
对应 的作用时间 对应 的作用时间- 开关序列:
对应的相电压(中心对齐)占空比为:
其他扇区类似,只需重新分配
完整代码
void motor_set_e_theta_omega(Motor *self, float e_theta, float e_omega)
{
e_theta = _normlalizeAngle(e_theta);
self->e_theta = e_theta;
self->e_omega = e_omega;
self->sin_e_theta = _sin(e_theta);
self->cos_e_theta = _cos(e_theta);
}
/**
* 设置dq轴电压
* - 为防止重复计算三角函数 需要先调用 motor_set_e_theta_omega
*/
void motor_set_dq_voltage(Motor *self, float Ud, float Uq)
{
self->Ud = Ud;
self->Uq = Uq;
// 帕克逆变换
// Ualpha = cos(θ) * Ud - sin(θ) * Uq
// Ubeta = sin(θ) * Ud + cos(θ) * Uq
self->Ualpha = self->cos_e_theta * Ud - self->sin_e_theta * Uq;
self->Ubeta = self->sin_e_theta * Ud + self->cos_e_theta * Uq;
switch (self->modulation)
{
case SPWM: // 克拉克逆变换
{
#define M_SQRT3_2 0.8660254037844386 // (sqrt(3)/2)
// 克拉克逆变换(等赋值形式)
// Ua = Ualpha
// Ub = -0.5 * Ualpha + (sqrt(3)/2) * Ubeta
// Uc = -0.5 * Ualpha - (sqrt(3)/2) * Ubeta = -(Ua + Ub) // 基尔霍夫电压电流定律
self->Ua = self->Ualpha;
self->Ub = -0.5f * self->Ualpha + M_SQRT3_2 * self->Ubeta;
self->Uc = -(self->Ua + self->Ub);
// 计算PWM占空比
// [-power_supply,+power_supply] => [-0.5,+0.5] => [0,1]
self->Ta = self->Ua / self->power_supply * 0.5f + 0.5f;
self->Tb = self->Ub / self->power_supply * 0.5f + 0.5f;
self->Tc = self->Uc / self->power_supply * 0.5f + 0.5f;
}
break;
case SVPWM:
{
#define M_PI_3 1.0471975511965979 // 60° = PI/3
int sector = self->e_theta / M_PI_3;
float alpha = self->e_theta - sector * M_PI_3;
// Uq∈[-power_supply,+power_supply]
// self->Uq / self->power_supply ∈ [-1,1]
float T1 = self->Uq / self->power_supply * _sin(M_PI_3 - alpha);
float T2 = self->Uq / self->power_supply * _sin(alpha);
float T0 = 1 - T1 - T2;
float Ta, Tb, Tc;
switch (sector)
{
case 0:
Ta = T1 + T2 + T0 / 2;
Tb = T2 + T0 / 2;
Tc = T0 / 2;
break;
case 1:
Ta = T1 + T0 / 2;
Tb = T1 + T2 + T0 / 2;
Tc = T0 / 2;
break;
case 2:
Ta = T0 / 2;
Tb = T1 + T2 + T0 / 2;
Tc = T2 + T0 / 2;
break;
case 3:
Ta = T0 / 2;
Tb = T1 + T0 / 2;
Tc = T1 + T2 + T0 / 2;
break;
case 4:
Ta = T2 + T0 / 2;
Tb = T0 / 2;
Tc = T1 + T2 + T0 / 2;
break;
case 5:
Ta = T1 + T2 + T0 / 2;
Tb = T0 / 2;
Tc = T1 + T0 / 2;
break;
default:
Ta = 0;
Tb = 0;
Tc = 0;
}
// 相电压
// [0,1] => [-0.5, 0.5] => [-power_supply, +power_supply]
self->Ua = (Ta - 0.5) * self->power_supply;
self->Ub = (Tb - 0.5) * self->power_supply;
self->Uc = (Tc - 0.5) * self->power_supply;
// pwm占空比
self->Ta = Ta;
self->Tb = Tb;
self->Tc = Tc;
}
break;
default:
break;
}
}输出效果

参考代码
- 一分钟玩转FOC SVPWM https://www.bilibili.com/video/BV1PC411n7QQ
- ESP32单片机仿真代码: https://wokwi.com/projects/396507548266030081