1. 编码器测速原理与M法工程实现
在永磁同步电机(PMSM)的有感FOC控制中,实时、准确的速度反馈是电流环与速度环协同工作的基础。编码器作为最常用的旋转位置传感器,其输出的A/B/Z三相信号不仅提供电角度信息,更蕴含着丰富的机械运动学特征。但原始脉冲信号本身并不直接等价于转速——它必须经过时间域或计数域的量化处理,才能转化为控制系统可识别的速度量。工程实践中,M法(频率测量法)与T法(周期测量法)是两种主流的数字测速策略,二者在精度、响应性、资源开销及适用工况上存在本质差异,绝非简单的“二选一”问题,而是需要根据电机运行区间、MCU性能边界与控制带宽要求进行系统性权衡。
1.1 M法与T法的本质差异与适用边界
M法的核心思想是在一个 固定的时间窗口 内,对编码器输出的脉冲个数进行累加,再通过单位时间内的脉冲密度反推角速度。其数学表达为:
$$
n = \frac{60 \times N}{P \times T_s} \quad \text{(rpm)}
$$
其中,$n$ 为电机转速(rpm),$N$ 为采样周期 $T_s$ 内捕获的总脉冲数,$P$ 为编码器每转输出的线数(即PPR,Pulses Per Revolution),60为分钟与秒的换算系数。
T法则完全相反:它不预设时间窗口,而是 精确测量相邻两个Z相脉冲(或A/B相边沿)之间的时间间隔 $\Delta t$ ,再通过倒数关系计算瞬时速度:
$$
n = \frac{60}{P \times \Delta t} \quad \text{(rpm)}
$$
表面上看,T法似乎具有更高的瞬时分辨率,尤其在极低速(如$\Delta t > 100\,\text{ms}$)时,单次测量即可获得有效速度值。然而,这种优势是以牺牲系统稳定性为代价的。当电机进入中高速区(例如$n > 300\,\text{rpm}$),$\Delta t$ 可能缩短至微秒级,导致中断触发频率急剧升高。以一款1024线编码器为例,在3000 rpm下,Z相脉冲间隔仅为 $ \frac{60}{3000 \times 1} = 20\,\text{ms} $,而A/B相四倍频后,有效边沿间隔仅为 $5\,\text{ms}$;若采用T法对每个上升沿计时,CPU将被高达200 kHz的中断淹没,严重挤占FOC核心算法(Clarke/Park变换、PI调节、SVPWM生成)的执行时间,最终导致控制环路失稳。
M法则天然规避了这一风险。其采样周期 $T_s$ 是人为可控的系统参数,通常设定在1 ms至10 ms之间(对应1 kHz–100 Hz采样率)。在此约束下,即使电机满负荷运行,单位周期内捕获的脉冲数 $N$ 也处于一个稳定、可预测的范围内。例如,同为1024线编码器,在3000 rpm下,1 ms周期内平均捕获脉冲数约为 $ \frac{1024 \times 4 \times 3000}{60 \times 1000} \approx 205 $,远低于定时器计数器的溢出阈值,且中断负载恒定。因此,M法在中高速段展现出卓越的鲁棒性与确定性,成为绝大多数工业驱动器的默认选择。
但M法并非没有缺陷。其最大误差来源于“±1个脉冲”的量化误差。在极低速(如$n < 10\,\text{rpm}$)时,$T_s$ 周期内可能仅捕获0或1个脉冲,导致速度计算结果剧烈跳变(0 rpm ↔ 非零rpm),表现为明显的“爬行”或“抖动”。此时,T法凭借其对时间间隔的亚微秒级分辨能力,反而能提供更平滑的低速响应。因此,一个成熟的驱动方案往往采用 M/T复合测速 :在中高速区启用M法,在低速区自动切换至T法,并通过滤波算法平滑过渡。本章聚焦于M法的工程落地,因其构成了整个速度环的主体工作区间。
1.2 STM32定时器6的精准配置与中断调度
M法的实现高度依赖一个高精度、低抖动的基准时钟源。在STM32F4系列MCU中,通用定时器(如TIM6、TIM7)因其结构简单、无输入捕获/输出比较通道、仅支持向上计数与更新中断等特性,成为实现周期性测速任务的理想载体。它不参与任何波形生成或复杂时序控制,纯粹作为一个“心跳发生器”,确保测速函数以严格恒定的间隔被执行。
本项目选用TIM6,其时钟源来自APB1总线。根据STM32F4xx参考手册,APB1的最大频率为42 MHz,而TIM6的时钟输入为APB1时钟的1倍(无预分频),故其计数器时钟频率为42 MHz。但字幕中提及“定时器6的总限频率170兆”,此为明显口误,实际应为 系统主频(SYSCLK)170 MHz ,而TIM6挂载于APB1总线下,其时钟受APB1预分频器影响。标准配置下,若SYSCLK=168 MHz,APB1预分频为2,则APB1=84 MHz,TIM6时钟即为84 MHz。此处我们按工程实际校准:假设系统时钟配置为168 MHz,APB1总线预分频为2,TIM6时钟为84 MHz。
为获得1 ms的精确中断周期,需设置:
-
预分频器(PSC)
:83(即84分频,因寄存器值为实际分频系数减1)
-
自动重装载值(ARR)
:999(即计数到1000个时钟周期)
计算验证:$T_{\text{interrupt}} = \frac{(PSC+1) \times (ARR+1)}{f_{\text{CLK}}} = \frac{84 \times 1000}{84\,\text{MHz}} = 1\,\text{ms}$。该配置确保了中断服务函数(ISR)每毫秒准时触发一次,为后续的编码器数据采集提供了严格的时间标尺。
在HAL库框架下,TIM6的初始化代码如下:
// 定时器6初始化:1ms更新中断
TIM_HandleTypeDef htim6;
htim6.Instance = TIM6;
htim6.Init.Prescaler = 83; // 84分频
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 999; // 1000个计数周期
htim6.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK) {
Error_Handler();
}
// 启用更新中断
if (HAL_TIM_Base_Start_IT(&htim6) != HAL_OK) {
Error_Handler();
}
关键点在于
HAL_TIM_Base_Start_IT()
的调用,它不仅启动了定时器计数器,更重要的是使能了更新事件(UEV)中断,并将其优先级纳入NVIC中断控制器的统一管理。在
stm32f4xx_it.c
中,必须定义对应的中断服务函数:
// TIM6中断服务函数
void TIM6_DAC_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim6);
}
而
HAL_TIM_IRQHandler()
内部会自动检测中断标志位,并调用用户注册的回调函数
HAL_TIM_PeriodElapsedCallback()
。因此,真正的测速逻辑应封装于此回调中,确保其执行时机与硬件中断严格同步,避免因软件延迟引入额外的时序误差。
1.3 编码器状态读取与Z相脉冲累计机制
ABZ编码器的A、B两相输出正交方波,其相位差为90度,用于判断旋转方向;Z相则为每转发出一个脉冲的索引信号,用于精确定位零点。在STM32中,通常利用TIM1/TIM2/TIM3/TIM4/TIM5的编码器接口模式(Encoder Interface Mode)来硬件解码A/B相,自动完成计数与方向识别。但本项目采用 软件解码 方式,原因在于其对底层逻辑的完全掌控力,便于理解测速算法的每一个细节,且在资源允许的情况下,软件解码的精度与可靠性完全满足工业级要求。
软件解码的核心是
在固定时刻(即TIM6的1ms中断)读取GPIO引脚电平状态
。假设A相接GPIOA_Pin8,B相接GPIOA_Pin9,Z相接GPIOA_Pin10。读取操作必须是原子的,即在同一时刻获取三个引脚的状态快照,以避免因A/B相边沿过渡期间的电平不确定性导致方向误判。HAL库提供的
HAL_GPIO_ReadPin()
函数虽安全,但三次调用存在微小时间差。更优的做法是直接读取GPIO端口的输入数据寄存器(IDR):
// 一次性读取GPIOA端口所有引脚状态
uint32_t gpioa_idr = GPIOA->IDR;
uint8_t a_level = (gpioa_idr & GPIO_PIN_8) ? 1 : 0;
uint8_t b_level = (gpioa_idr & GPIO_PIN_9) ? 1 : 0;
uint8_t z_level = (gpioa_idr & GPIO_PIN_10) ? 1 : 0;
此操作在一个指令周期内完成,保证了状态的一致性。
Z相脉冲的累计是M法实现的关键环节。由于Z相仅在每转一圈时产生一个窄脉冲(典型宽度为几微秒至几十微秒),而我们的采样周期为1 ms,因此
无法依赖1ms中断来捕获Z脉冲
——脉冲极可能在两次采样之间“溜走”。正确的做法是:
将Z相引脚配置为外部中断(EXTI)输入,一旦检测到上升沿(或下降沿),立即在中断服务程序中对全局变量
z_count
进行原子累加
。
在STM32CubeMX或手动配置中,需执行以下步骤:
- 将GPIOA_Pin10配置为
GPIO_MODE_IT_RISING
(上升沿触发)
- 使能SYSCFG时钟,并将PA10映射到EXTI线10
- 使能EXTI线10的中断,并在NVIC中设置其优先级(建议高于TIM6中断,确保Z脉冲不丢失)
- 在
EXTI15_10_IRQHandler
中编写中断服务函数
// Z相外部中断服务函数
void EXTI15_10_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_10) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_10); // 清除中断标志
z_count++; // 原子累加,因中断频率极低,无需额外保护
}
}
z_count
变量记录了自系统上电以来,电机总共旋转了多少整圈。它与编码器计数值共同构成了完整的“绝对位置”信息,是计算跨圈脉冲差值的基础。
1.4 跨圈脉冲差值计算与速度公式推导
编码器计数器(通常由TIMx的计数器寄存器CNT提供)是一个有限位宽的循环计数器。以12位编码器为例,其计数范围为0–4095。当电机正向旋转时,计数值从0递增至4095,然后溢出回0,继续递增;反向旋转时则从0递减至4095(补码表示),再递减。因此,单纯计算两次采样间的
cnt_new - cnt_old
差值,会在溢出点产生巨大跳变(如4095→0时,差值为-4095而非+1),导致速度计算完全错误。
M法的精髓在于,它必须能够 无缝处理计数器的自然溢出与Z相脉冲的整圈累加 ,从而得到真实的、无跳变的“总脉冲增量”。其计算逻辑分为三步:
第一步:获取当前计数值与Z相圈数
在TIM6的1ms中断回调中,首先读取当前TIMx(假设为TIM2)的计数器值
cnt_now
,并保存上一次采样时的值
cnt_last
。同时,读取当前
z_count
值,并保存上一次的
z_last
。
第二步:计算净增量
根据A/B相电平判断当前旋转方向
dir
(+1为正转,-1为反转)。然后,依据方向与Z相变化,计算
cnt_now
与
cnt_last
之间的有效差值
delta_cnt
:
-
若
dir == +1(正转): -
若
z_count == z_last:说明未发生整圈翻转,delta_cnt = cnt_now - cnt_last -
若
z_count > z_last:说明发生了z_count - z_last次整圈翻转,且最后一次翻转发生在cnt_now之前,因此delta_cnt = cnt_now + (ENC_MAX - cnt_last) + (z_count - z_last - 1) * ENC_MAX
(其中ENC_MAX = 4096为计数器满量程值) -
若
dir == -1(反转): -
若
z_count == z_last:delta_cnt = cnt_now - cnt_last(注意此时cnt_now < cnt_last,结果为负) -
若
z_count < z_last:说明发生了z_last - z_count次整圈翻转,delta_cnt = cnt_now - (ENC_MAX - cnt_last) - (z_last - z_count - 1) * ENC_MAX
上述逻辑可简化为一个统一的公式,其核心思想是:
将
cnt_last
视为一个“锚点”,计算从该锚点出发,经过若干整圈和部分圈后,到达
cnt_now
所跨越的总脉冲数
。一个更简洁、鲁棒的实现是使用32位有符号整数存储“扩展计数值”:
int32_t extended_cnt_last = (int32_t)z_last * ENC_MAX + cnt_last;
int32_t extended_cnt_now = (int32_t)z_count * ENC_MAX + cnt_now;
int32_t delta_cnt = extended_cnt_now - extended_cnt_last;
此方法将Z相圈数与当前计数值线性叠加,彻底消除了溢出判断的复杂性,且计算开销极小,是嵌入式领域的经典技巧。
第三步:代入速度公式
得到
delta_cnt
后,代入M法基本公式:
$$
n = \frac{60 \times \delta_{cnt}}{P \times T_s \times \text{dir}}
$$
其中,$P$ 为编码器PPR(如1024),$T_s = 0.001\,\text{s}$(1ms),$\text{dir}$ 为方向标识(+1或-1),确保结果$n$的符号正确反映旋转方向。最终结果单位为rpm。
1.5 工程代码实现与在线调试验证
将上述逻辑整合为一个独立的测速函数
GetMotorSpeed_RPM()
,其设计遵循高内聚、低耦合原则,所有状态变量均声明为
static
,对外仅暴露一个无参接口,返回当前计算出的速度值(int16_t,单位rpm):
// 编码器测速模块(encoder_speed.c)
#include "main.h"
#include "encoder_speed.h"
#define ENC_PPR 1024 // 编码器线数
#define ENC_MAX 4096 // 12位计数器满量程
#define SAMPLE_TIME_MS 1 // 采样周期(ms)
static uint16_t cnt_last = 0; // 上次计数值
static uint32_t z_last = 0; // 上次Z相圈数
static int16_t speed_rpm = 0; // 当前速度(rpm)
// TIM6更新中断回调:执行测速
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM6) {
uint16_t cnt_now;
uint32_t z_now;
int8_t dir;
// 1. 读取当前计数值与方向(假设已由其他函数更新)
cnt_now = GetEncoderCount(); // 此函数返回TIMx->CNT值
dir = GetEncoderDirection(); // 此函数根据A/B相电平返回+1/-1
z_now = z_count; // 读取全局Z计数器
// 2. 计算扩展计数值差值
int32_t ext_cnt_last = (int32_t)z_last * ENC_MAX + cnt_last;
int32_t ext_cnt_now = (int32_t)z_now * ENC_MAX + cnt_now;
int32_t delta_cnt = ext_cnt_now - ext_cnt_last;
// 3. 计算速度(rpm)
// 注意:60 * delta_cnt / (PPR * Ts_ms) = 60000 * delta_cnt / (PPR * 1)
int32_t speed_raw = (60000L * delta_cnt) / ENC_PPR;
speed_rpm = (int16_t)speed_raw;
// 4. 更新历史状态
cnt_last = cnt_now;
z_last = z_now;
}
}
// 对外接口:获取当前速度
int16_t GetMotorSpeed_RPM(void)
{
return speed_rpm;
}
该函数被置于
HAL_TIM_PeriodElapsedCallback()
中,确保其执行严格同步于1ms硬件定时器,杜绝了软件延时带来的采样抖动。
调试阶段,我们通过串口(USART2)将
speed_rpm
值以ASCII格式发送至上位机(如Windows的“WolfShang为机”或Linux的
screen
/
minicom
)。在
main()
循环中添加:
char buf[32];
while (1) {
sprintf(buf, "Speed: %d rpm\r\n", GetMotorSpeed_RPM());
HAL_UART_Transmit(&huart2, (uint8_t*)buf, strlen(buf), HAL_MAX_DELAY);
HAL_Delay(100); // 每100ms发送一次,避免刷屏
}
在实际电机运行测试中,观察到:当FOC算法中的q轴电压指令
Uq
增大时,电机加速,串口打印的速度值稳步上升;当
Uq
设为负值时,电机反转,速度值显示为负,且其绝对值与正转时对称。这证明了测速逻辑的方向判别与幅值计算均准确无误。更重要的是,速度值的变化平滑、无毛刺,表明Z相中断与TIM6中断的协同工作稳定可靠,跨圈计算逻辑经受住了长时间连续运行的考验。
2. 从SPWM到SVPWM:驱动策略的范式升级
在完成ABZ编码器的有感SPWM驱动与速度闭环后,整个控制系统已具备了基本的运动控制能力。然而,SPWM作为一种经典的正弦波调制技术,其固有的局限性开始显现:在相同的母线电压下,它所能输出的最大基波电压幅值仅为 $V_{dc}/2$(忽略死区影响),这意味着电机绕组的有效电压利用率仅为50%。对于追求高功率密度、高效率与宽调速范围的现代驱动器而言,这一瓶颈已成为进一步提升性能的天花板。SVPWM(Space Vector Pulse Width Modulation,空间矢量脉宽调制)正是为突破此限制而生的先进调制策略。它不再将三相电压视为彼此独立的正弦量,而是将其抽象为复平面上的一个旋转空间矢量,通过对八个基本电压矢量(包括六个非零矢量与两个零矢量)的合理组合与作用时间分配,实现了对目标电压矢量的最优逼近,从而将直流母线电压的利用率提升至理论极限 $V_{dc}/\sqrt{3} \approx 0.866 V_{dc}$,较SPWM提升了约15.5%。
2.1 SPWM的物理局限与SVPWM的几何直觉
理解SVPWM的第一步,是摒弃“三相正弦波”的传统视角,建立“二维平面矢量”的新认知。在三相静止坐标系(ABC)中,任意时刻的三相电压$(V_a, V_b, V_c)$满足约束$V_a + V_b + V_c = 0$(忽略零序分量)。通过Clark变换,可将其映射到两相正交坐标系(αβ):
$$
\begin{bmatrix}
V_\alpha \
V_\beta
\end{bmatrix}
=
\frac{2}{3}
\begin{bmatrix}
1 & -\frac{1}{2} & -\frac{1}{2} \
0 & \frac{\sqrt{3}}{2} & -\frac{\sqrt{3}}{2}
\end{bmatrix}
\begin{bmatrix}
V_a \
V_b \
V_c
\end{bmatrix}
$$
该变换将三维空间压缩为二维平面,$V_\alpha$与$V_\beta$共同构成一个复数矢量$V_s = V_\alpha + jV_\beta$,其模长$|V_s|$代表合成电压的幅值,相角$\theta = \tan^{-1}(V_\beta/V_\alpha)$代表其在平面内的方向。一个理想的正弦电压指令,对应于$V_s$在αβ平面上以恒定角速度$\omega$做匀速圆周运动。
SPWM的实现,是将$V_s$的α、β分量分别作为调制波,与一个高频三角载波进行比较,生成六路PWM信号。其本质是“分而治之”,并未考虑三者之间的内在耦合关系。因此,当$V_s$的轨迹接近正六边形的顶点时(即某相电压接近$V_{dc}$,另两相接近$-V_{dc}/2$),SPWM的输出已达到饱和,无法再增大$|V_s|$。
SVPWM则采取了截然不同的思路。它将逆变器的八种开关状态($S_a, S_b, S_c$,每个为0或1)映射为αβ平面上的八个离散电压矢量:
- $V_0(000)$: $(0, 0)$
- $V_7(111)$: $(0, 0)$
- $V_1(100)$: $(\frac{2}{3}V_{dc}, 0)$
- $V_2(110)$: $(\frac{1}{3}V_{dc}, \frac{\sqrt{3}}{3}V_{dc})$
- $V_3(010)$: $(-\frac{1}{3}V_{dc}, \frac{\sqrt{3}}{3}V_{dc})$
- $V_4(011)$: $(-\frac{2}{3}V_{dc}, 0)$
- $V_5(001)$: $(-\frac{1}{3}V_{dc}, -\frac{\sqrt{3}}{3}V_{dc})$
- $V_6(101)$: $(\frac{1}{3}V_{dc}, -\frac{\sqrt{3}}{3}V_{dc})$
这六个非零矢量首尾相连,恰好构成一个正六边形,其外接圆半径即为$V_{dc}/\sqrt{3}$。SVPWM的核心任务,就是在每个PWM周期$T_s$内,选择该六边形内与目标矢量$V_s$最邻近的两个非零矢量$V_x$、$V_y$,以及一个零矢量($V_0$或$V_7$),并通过精确控制它们的作用时间$T_x$、$T_y$、$T_0$,使得其合成效果等效于$V_s$,即满足:
$$
V_s \cdot T_s = V_x \cdot T_x + V_y \cdot T_y + V_0 \cdot T_0
$$
且$T_x + T_y + T_0 = T_s$。通过求解该矢量方程,即可得到$T_x$、$T_y$、$T_0$的解析表达式。这一过程,本质上是将连续的圆形轨迹,用一系列离散的直线段(矢量)进行最优拟合,其几何直观性远超SPWM的三角波比较。
2.2 SVPWM的七段式实现与扇区判断
SVPWM的算法实现可分为三个关键步骤:扇区判断、作用时间计算、PWM波形生成。其中,扇区判断是整个流程的起点,它决定了后续计算所采用的公式。
由于六个非零矢量将αβ平面划分为六个60度的扇区(Sector I–VI),目标矢量$V_s$必然位于其中一个扇区内。判断方法极为简洁:仅需检查$V_\alpha$、$V_\beta$及其线性组合$V_\beta - \sqrt{3}V_\alpha$、$V_\beta + \sqrt{3}V_\alpha$的符号。一个高效的实现是:
// 根据V_alpha, V_beta判断扇区(1-6)
uint8_t sector = 0;
if (V_beta >= 0) {
if (V_alpha >= 0) {
sector = (V_beta > SQRT3 * V_alpha) ? 2 : 1;
} else {
sector = (V_beta > -SQRT3 * V_alpha) ? 2 : 3;
}
} else {
if (V_alpha >= 0) {
sector = (V_beta < -SQRT3 * V_alpha) ? 6 : 1;
} else {
sector = (V_beta < SQRT3 * V_alpha) ? 6 : 5;
}
}
此处
SQRT3
为$\sqrt{3}$的定点数近似值(如1732/1000)。一旦确定扇区,即可查表获取该扇区内构成的两个相邻非零矢量编号(如Sector I由$V_1$和$V_2$构成),并代入对应的作用时间公式。
以Sector I为例,其时间计算公式为:
$$
T_1 = T_s \cdot \frac{\sqrt{3}}{V_{dc}} (V_\beta - \frac{1}{\sqrt{3}} V_\alpha), \quad
T_2 = T_s \cdot \frac{2}{V_{dc}} V_\alpha, \quad
T_0 = T_s - T_1 - T_2
$$
所有扇区的公式均可统一为:
$$
T_x = T_s \cdot \frac{2}{V_{dc}} \cdot |V_s| \cdot \cos(\theta - \theta_x), \quad
T_y = T_s \cdot \frac{2}{V_{dc}} \cdot |V_s| \cdot \cos(\theta - \theta_y)
$$
其中$\theta_x$、$\theta_y$为矢量$V_x$、$V_y$的相角。但在嵌入式实现中,为避免耗时的三角函数运算,普遍采用上述基于扇区的查表法。
最后一步是将$T_x$、$T_y$、$T_0$转换为具体的PWM占空比,并分配给三相桥臂。七段式SVPWM(也称对称式)因其谐波含量低、开关损耗均衡而被广泛采用。它在一个PWM周期内,按特定顺序插入两个零矢量($V_0$和$V_7$)和两个非零矢量,形成七段波形。例如,在Sector I中,其序列是:$V_0 \to V_1 \to V_2 \to V_7 \to V_2 \to V_1 \to V_0$。每一段的持续时间由$T_0/4$、$T_1/2$、$T_2/2$、$T_0/4$、$T_2/2$、$T_1/2$、$T_0/4$决定。最终,通过将这些时间段累加,即可得到三相各自的“开通时间”$T_a$、$T_b$、$T_c$,并将其写入TIM1的捕获/比较寄存器(CCR1/CCR2/CCR3),从而生成最终的PWM波形。
2.3 从SPWM到SVPWM的工程迁移路径
将现有SPWM驱动平滑迁移到SVPWM,并非推倒重来,而是一次模块化的升级。其核心在于: 保持FOC算法的上层架构(Park/Clarke变换、PI调节器)完全不变,仅替换最底层的PWM生成模块 。
具体迁移步骤如下:
1.
硬件准备
:确认TIM1(高级定时器)已配置为互补PWM输出模式,并正确连接至三相逆变桥的上/下桥臂驱动芯片。TIM1的时基(ARR)需重新设定,以匹配新的PWM开关频率(如10 kHz)。
2.
算法移植
:将SVPWM计算函数(
SVPWM_Generate()
)集成进工程。该函数输入为$d$、$q$轴电压指令$V_d$、$V_q$,输出为三相占空比
duty_a
、
duty_b
、
duty_c
(归一化到0–1)。
3.
坐标变换接入
:在FOC主循环中,将Park反变换(IPark)的输出$(V_\alpha, V_\beta)$,直接作为
SVPWM_Generate()
的输入,取代原先SPWM调制函数的输入。
4.
死区时间注入
:SVPWM对上下桥臂的时序要求更为严苛,必须在互补PWM通道间插入精确的死区时间(Dead Time),以防止直通短路。此功能由TIM1的BDTR寄存器硬件支持,需在初始化时配置
DeadTime
参数。
5.
调试与验证
:使用示波器观测三相PWM波形,验证其七段式结构、对称性及死区时间是否符合预期;同时监测母线电流波形,对比SPWM与SVPWM下的谐波含量与转矩脉动。
此次升级的意义远不止于15%的电压利用率提升。它为后续引入更高级的控制策略(如三次谐波注入、过调制控制、模型预测控制)奠定了坚实的基础。当我们在下一章真正踏入SVPWM的代码世界时,那些看似繁复的扇区判断与时间计算,将不再是令人畏惧的数学迷宫,而是一套清晰、优雅、且已被无数工业产品验证过的工程范式。它标志着我们的FOC系统,正从“能转起来”迈向“转得更高效、更平稳、更智能”的新阶段。

150

被折叠的 条评论
为什么被折叠?



