1. 电流环延迟这件事,为什么值得单独拎出来讲
搞电机控制的人,迟早会撞上同一个问题:电流环带宽提不上去,PI参数怎么调都别扭,波形看着还行但动态响应就是慢半拍。很多人第一反应是PI参数没整定好,或者PWM频率不够高,于是拼命往上堆开关频率,结果发热上去了、效率下来了,带宽还是那个死样子。我早年也在这个坑里蹲了很久,后来才慢慢意识到,问题往往不在PI本身,而在于采样到更新的这条路径上,藏着一拍甚至两拍的延迟。
FOC(磁场定向控制)的电流环本质上是一个数字控制系统,数字控制跟模拟控制最大的区别就是:它不可能"实时"响应。你采样到的电流值,是某个时刻的;你算出来的占空比,要等到下一个(或下下个)PWM周期才真正作用到电机上。这中间的时间差,就是延迟。延迟本身不可怕,可怕的是很多人根本不知道自己用的策略到底引入了多少延迟,也不知道不同策略之间差在哪里。
SSSU、DSDU、SSDU、DSSU这四个缩写,说的就是采样时刻和更新时刻的四种组合方式。S是Single(单次),D是Double(双次),四个字母两两一组,前两个字母描述采样行为,后两个字母描述更新行为。别看只是四个字母的排列组合,它们对应的电流环延迟可以从0.5个PWM周期一路差到1.5个PWM周期,反映到闭环带宽上就是成倍的差距。这篇文章我就把这四种策略掰开揉碎讲清楚,包括它们各自的延迟来源、适用场景、以及我在实际项目里踩过的坑。
注意:本文讨论的延迟均以PWM周期T_pwm为基本单位,默认采用中心对齐PWM模式,这是目前绝大多数FOC实现的标准配置。
2. 先把底层时序逻辑捋顺,否则后面全是糊涂账
2.1 PWM周期、采样时刻与更新时刻的定义
要理解四种策略,得先把三个时间概念钉死。PWM周期T_pwm,就是三角载波从谷底爬到峰顶再回到谷底的时间,中心对齐模式下计数器先向上数再向下数。采样时刻,指的是ADC触发、读取相电流的那一瞬间。更新时刻,指的是新的占空比寄存器值被写入、从下一个PWM周期开始生效的那个点。
在中心对齐PWM里,有几个天然的"事件点":计数器过零(谷底)、计数器到达峰值(峰顶)、以及过零和峰顶之间的中点。这些事件点就是采样和更新的候选位置。为什么是这些点?因为中心对齐PWM的对称性使得这些位置上的开关噪声最小,采样质量最高。具体来说,谷底和峰顶附近是下桥臂全开的时间窗口,电流采样最干净。
2.2 为什么采样和更新不能随便放
有人会想,那我采样完立刻更新不就行了?理论上可以,但实际不行。原因有两个:第一,ADC转换需要时间,从触发到结果可用通常要几百纳秒到一两微秒;第二,FOC的计算量不小,Clarke、Park、PI、反Park、SVPWM这一套跑下来,在中低端MCU上可能要好几微秒。你采样完根本来不及算完就更新,所以必须把更新时刻安排到下一个事件点。
这就引出了核心矛盾:采样时刻和更新时刻之间的间隔,直接决定了电流环的有效延迟。间隔越短,延迟越小,带宽越高;间隔越长,延迟越大,但计算时间越充裕。四种策略本质上就是在这个矛盾里做不同的取舍。
2.3 延迟对电流环带宽的定量影响
先给一个粗略但实用的估算公式。数字控制系统的延迟T_d会引入一个相位滞后,在频率f处的相位损失约为:
φ_loss = 2π × f × T_d假设PWM频率为10kHz(T_pwm = 100μs),电流环目标带宽为1kHz。如果延迟是1个PWM周期(100μs),那么相位损失为:
φ_loss = 2π × 1000 × 100e-6 = 0.628 rad ≈ 36°如果延迟是1.5个周期(150μs),相位损失就是54°。相位裕度本来可能只有45°到60°,再吃掉36°到54°,系统不振荡才怪。这就是为什么很多人发现电流环带宽卡在开关频率的1/10左右上不去——延迟在作祟。
反过来说,如果你能把延迟从1.5个周期压到0.5个周期,同样的相位裕度下,带宽理论上可以提升三倍。这就是研究这四种策略的实际意义。
3. 四种策略逐一拆解:SSSU、DSDU、SSDU、DSSU到底差在哪
3.1 SSSU:单采样单更新,最经典也最保守
SSSU的全称是Single Sample Single Update。采样在每个PWM周期的固定一个点进行,更新也在每个周期的固定一个点进行。典型配置是:在计数器过零(谷底)时触发ADC采样,然后在下一个谷底更新占空比。
这种策略的时序是这样的:第n个周期谷底采样,第n个周期内完成计算,第n+1个周期谷底更新。从采样到更新的间隔是整整一个PWM周期,加上ADC转换和计算时间,实际延迟约为1到1.2个PWM周期。
SSSU的优点是实现简单、计算时间充裕、对MCU性能要求低。缺点是延迟大,电流环带宽受限。我早期用STM32F103做FOC时就是用的SSSU,10kHz PWM下电流环带宽做到800Hz左右就顶天了,再往上调PI就开始振荡。
实操心得:SSSU下如果非要提带宽,可以尝试把PWM频率提到20kHz,但要注意MOSFET开关损耗和死区时间占比。死区时间在20kHz下如果还是1μs,那占空比损失就很可观了。
3.2 DSDU:双采样双更新,延迟最小的激进方案
DSDU是Double Sample Double Update。顾名思义,每个PWM周期采样两次、更新两次。典型配置是:谷底采样一次,峰顶采样一次;谷底更新一次,峰顶更新一次。这样采样到更新的间隔就缩短到了半个PWM周期。
时序上:第n个周期谷底采样,半个周期内完成计算,峰顶更新;峰顶采样,半个周期内完成计算,下一个谷底更新。平均延迟约为0.5到0.7个PWM周期。
DSDU的延迟最小,电流环带宽可以做到开关频率的1/5甚至更高。但代价也很明显:计算时间被压缩到半个PWM周期,对MCU算力要求高;同时每个周期要算两次FOC,CPU负载翻倍。我在用STM32G4做DSDU时,10kHz PWM下半个周期只有50μs,FOC计算加上ADC中断处理,余量已经很紧张了。
还有一个容易被忽略的问题:双采样会引入采样噪声的不对称。谷底和峰顶的开关噪声环境不完全一样,如果ADC采样窗口设置不当,两次采样的电流值可能有系统性偏差,导致电流波形出现偶次谐波。这个问题我在一个低压大电流项目里遇到过,后来通过调整采样窗口和增加RC滤波才解决。
3.3 SSDU:单采样双更新,折中方案的代表
SSDU是Single Sample Double Update。每个PWM周期只采样一次,但更新两次。典型配置是:谷底采样一次,然后在峰顶和下一个谷底各更新一次。
等等,只采样一次怎么更新两次?这里的关键在于:第一次更新用的是当前采样值算出的结果,第二次更新用的是同一个采样值算出的另一个结果(通常是基于预测或插值)。实际上,SSDU的第二次更新往往不是基于新采样,而是基于某种估算或保持。
更常见的SSDU实现是:谷底采样,峰顶更新一次(用新算出的占空比),谷底再更新一次(还是用同一个占空比,或者做一点微调)。这样从采样到第一次更新的延迟只有半个周期,到第二次更新是一个周期。
SSDU的延迟介于SSSU和DSDU之间,约为0.7到1个PWM周期。它的优势是计算时间比DSDU充裕(因为只需要算一次FOC),同时延迟又比SSSU小。缺点是第二次更新没有新采样支撑,动态性能不如DSDU。
注意:SSDU的第二次更新如果直接复用第一次的占空比,实际上等效于SSSU,延迟并没有改善。真正能降低延迟的SSDU实现,需要在第二次更新时使用某种预测算法,比如基于电流斜率的线性外推。这个后面会详细讲。
3.4 DSSU:双采样单更新,听起来矛盾但有其道理
DSSU是Double Sample Single Update。每个周期采样两次,但只更新一次。典型配置是:谷底和峰顶各采样一次,然后在下一个谷底统一更新。
这种策略看起来很奇怪:采样两次却只更新一次,那第二次采样不是浪费了吗?其实不然。DSSU的核心思想是用两次采样做平均或滤波,提高采样精度,同时保持更新的规律性。延迟方面,从第一次采样到更新约为1个周期,从第二次采样到更新约为0.5个周期,平均延迟约0.75个周期。
DSSU适合那些对电流采样精度要求高、但对动态响应要求不那么极致的场景。比如某些低速大扭矩应用,电流纹波大,单次采样容易受噪声影响,双采样平均能显著改善信噪比。
3.5 四种策略的横向对比
| 策略 | 采样次数/周期 | 更新次数/周期 | 平均延迟(T_pwm) | 计算负载 | 适用场景 |
|---|---|---|---|---|---|
| SSSU | 1 | 1 | 1.0~1.2 | 低 | 低成本、低带宽需求 |
| DSDU | 2 | 2 | 0.5~0.7 | 高 | 高带宽、高动态响应 |
| SSDU | 1 | 2 | 0.7~1.0 | 中 | 带宽与算力折中 |
| DSSU | 2 | 1 | 0.75~0.9 | 中 | 高精度采样、中带宽 |
这张表是我根据实际项目经验整理的,具体数值会因MCU性能、ADC速度、中断优先级等因素有出入,但相对关系是可靠的。
4. 延迟到底从哪来:把每一纳秒都算清楚
4.1 延迟的四个组成部分
很多人以为延迟就是"采样到更新"的时间差,其实这只是其中一部分。完整的电流环延迟包括四块:
第一块是ADC采样与转换延迟。从触发信号发出到ADC结果寄存器可用,这段时间包括采样保持时间和逐次逼近转换时间。以常见的12位ADC、采样时间1.5个ADC时钟周期为例,如果ADC时钟是60MHz,转换时间约0.2μs。看起来很小,但在50μs的半周期里也占了0.4%。
第二块是计算延迟。从ADC中断触发到FOC算法算完、占空比写入影子寄存器,这段时间取决于MCU主频和算法优化程度。STM32F4在168MHz下跑一次FOC大约2~3μs,STM32G4在170MHz下可以压到1.5μs左右。如果用定点运算,还能再快一些。
第三块是更新生效延迟。占空比写入影子寄存器后,要等到下一个更新事件才真正加载到活动寄存器。如果更新事件在写入之后很久才来,这段时间就是纯等待。
第四块是PWM输出延迟。从活动寄存器加载新值到实际输出波形变化,还有几个时钟周期的同步延迟,通常可以忽略,但在高频PWM下也要留意。
4.2 以DSDU为例的逐段计算
假设PWM频率10kHz,T_pwm = 100μs,半周期50μs。MCU为STM32G4,ADC转换0.2μs,FOC计算1.5μs。
谷底触发采样,ADC转换完成在0.2μs后,FOC计算在1.7μs后完成,占空比写入影子寄存器。峰顶更新事件在50μs时到来,新占空比生效。从采样到更新的延迟为:
T_delay = 50μs - 1.7μs ≈ 48.3μs ≈ 0.48 T_pwm再加上PWM输出延迟和电流实际响应时间,有效延迟约0.5~0.6个PWM周期。这跟理论值吻合。
4.3 为什么SSSU的延迟不是整整一个周期
SSSU理论延迟是1个周期,但实际测量往往在1.1到1.2之间。多出来的0.1到0.2来自哪里?主要是ADC转换和计算时间。因为SSSU的更新时刻固定在下一个谷底,而采样到计算完成的时间是"额外"的,它不会因为你算得快就提前更新。所以SSSU的延迟实际上是:
T_delay = T_pwm + T_adc + T_calc这就是为什么SSSU的延迟对MCU性能不敏感——你算得再快,也得等下一个谷底。反过来说,DSDU的延迟对计算时间就敏感得多,因为计算必须在半个周期内完成,算得慢就直接吃掉延迟余量。
5. 实测对比:四种策略在真实项目中的表现
5.1 测试平台与条件
我用一套自制的PMSM驱动板做了对比测试。电机是24V、额定功率200W的表贴式永磁同步电机,极对数4,额定转速3000rpm。驱动板用STM32G431,PWM频率10kHz,死区时间500ns。电流采样用两颗霍尔传感器,ADC触发由TIM1的CH4比较事件产生。电流环PI参数在每种策略下单独整定到临界振荡,然后回退20%作为最终参数。
测试项目包括:电流环阶跃响应上升时间、带宽(-3dB)、电流THD、以及突加负载时的恢复时间。
5.2 阶跃响应与带宽对比
| 策略 | 上升时间(μs) | -3dB带宽(Hz) | 超调量 |
|---|---|---|---|
| SSSU | 420 | 780 | 8% |
| DSDU | 180 | 2100 | 12% |
| SSDU | 280 | 1350 | 10% |
| DSSU | 310 | 1150 | 9% |
DSDU的带宽是SSSU的2.7倍,这个差距非常直观。SSDU和DSSU居中,符合预期。超调量方面,DSDU因为带宽高、相位裕度紧,超调略大,但通过调整PI的微分项可以压下来。
5.3 电流THD与噪声表现
有意思的是,DSDU虽然带宽最高,但电流THD并不是最好的。在低速轻载下,DSDU的THD反而比SSSU高0.5个百分点。原因前面提过:双采样引入了不对称噪声。后来我在ADC采样窗口前加了简单的RC滤波(1kΩ + 1nF,截止频率约160kHz),THD才降下来。
DSSU的THD表现最好,双采样平均的效果确实明显。在低速重载下,DSSU的电流波形明显比SSSU干净。
5.4 突加负载恢复时间
从空载突加50%额定负载,观察电流恢复到稳态的时间:
- SSSU:约2.5ms
- DSDU:约0.8ms
- SSDU:约1.4ms
- DSSU:约1.8ms
这个结果跟带宽排序基本一致。DSDU的动态响应确实快,适合那些负载变化剧烈的场合,比如电动工具、压缩机启动等。
实操心得:如果你的应用对动态响应要求不高,SSSU完全够用,没必要为了追求DSDU而换更贵的MCU。我见过不少项目盲目上DSDU,结果MCU算力不够,FOC计算超时,反而导致电流波形畸变。选策略之前先算清楚MCU的算力余量。
6. 怎么选:从应用需求反推策略
6.1 按带宽需求选
先问自己一个问题:电流环需要多快?如果只是风机、水泵这类负载,电流环带宽500Hz就够了,SSSU绰绰有余。如果是伺服驱动、机器人关节,需要1kHz以上带宽,那就得考虑DSDU或SSDU。如果是高性能数控机床、飞轮储能,带宽要求2kHz以上,DSDU是唯一选择。
6.2 按MCU算力选
算力是硬约束。一个简单的估算方法:FOC计算时间乘以2(DSDU要算两次)必须小于半个PWM周期,且留30%余量。比如你的FOC计算要3μs,DSDU下每周期算两次就是6μs,半周期如果是25μs(20kHz PWM),余量还有19μs,够用。但如果PWM频率是20kHz、半周期25μs,而你的FOC计算要8μs,两次就是16μs,余量只剩9μs,中断嵌套一多就容易超时。
6.3 按采样精度需求选
如果电机电流纹波大、或者低速时电流信号弱,DSSU的双采样平均能显著改善信噪比。我做过一个低速直驱项目,额定转速只有60rpm,电流频率极低,单次采样受开关噪声影响严重,换成DSSU后电流波形明显干净了。
6.4 混合策略:不是非得四选一
实际项目中,我经常用混合策略。比如低速时用DSSU保证采样精度,高速时切到DSDU保证带宽。切换逻辑可以基于转速或者电流幅值。这种动态切换需要在代码里做好状态机,切换瞬间要注意PI积分器的处理,避免突变。
7. 代码实现要点:以STM32G4为例
7.1 定时器与ADC配置
以DSDU为例,TIM1配置为中心对齐模式,ARR设为PWM周期的一半(因为中心对齐下实际周期是2×ARR)。CH4比较事件用于触发ADC:
// TIM1 中心对齐,ARR = 4250 对应 10kHz (170MHz / (2*4250*2)) TIM1->ARR = 4250; TIM1->CR1 |= TIM_CR1_CMS_0; // 中心对齐模式1 TIM1->CCR4 = 4250; // 谷底触发 // 峰顶触发用另一个比较通道或更新事件ADC配置为外部触发,触发源选TIM1_CH4,转换完成后产生中断或DMA请求。
7.2 中断优先级与计算时间保障
DSDU下,ADC中断和FOC计算必须在半个周期内完成。中断优先级要设到最高,且中断服务程序里不要做任何耗时操作。我通常把FOC计算放在ADC中断里直接跑,算完立刻写CCR寄存器。
void ADC1_2_IRQHandler(void) { // 读取电流 Ia = ADC1->JDR1; Ib = ADC2->JDR1; // Clarke + Park + PI + 反Park + SVPWM FOC_Run(); // 更新占空比 TIM1->CCR1 = Ta; TIM1->CCR2 = Tb; TIM1->CCR3 = Tc; ADC1->ISR |= ADC_ISR_JEOS; }7.3 采样窗口与噪声抑制
采样窗口要避开开关瞬间。中心对齐PWM下,谷底和峰顶附近是下桥臂全开的时间,电流采样最干净。但要注意死区时间的影响:死区期间电流续流路径变化,采样值可能失真。一般建议采样点设在谷底后1~2μs,等死区结束、电流稳定后再采。
注意:DSDU下峰顶采样时,如果上桥臂刚关断、下桥臂刚开通,电流可能还在续流,采样值会偏低。解决办法是适当延迟采样时刻,或者用双采样做差分校准。
8. 常见问题与排查技巧实录
8.1 电流波形出现偶次谐波
这是DSDU的典型问题。原因:谷底和峰顶采样值存在系统性偏差。排查方法:用示波器同时抓两路电流采样触发信号和实际电流波形,观察两次采样点的电流值是否对称。解决办法:调整采样窗口位置,或在两次采样之间做增益校准。
8.2 高带宽下PI振荡
带宽提上去后PI振荡,不一定是PI参数问题,可能是延迟补偿没做。在PI控制器里加入延迟补偿项,或者用预测电流控制替代传统PI。我试过在DSDU下用无差拍预测控制,带宽可以做到2.5kHz以上,但参数敏感性高,电机参数变化10%就可能失稳。
8.3 中断超时导致PWM异常
DSDU下如果FOC计算超时,占空比没及时更新,PWM输出会保持上一个周期的值,导致电流失控。排查方法:在中断里翻转一个GPIO,用示波器看中断执行时间。如果接近半周期,必须优化代码或降低PWM频率。
8.4 低速时电流采样不准
低速时电流频率低,单次采样可能采到纹波谷底或峰顶。解决办法:改用DSSU双采样平均,或者在采样前加模拟滤波。我通常会在霍尔输出后加一个截止频率约100kHz的RC滤波,效果不错。
8.5 四种策略的快速排查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 电流THD高 | 采样噪声大 | 检查采样窗口、加RC滤波 |
| 带宽上不去 | 延迟大 | 确认策略、检查更新时刻 |
| PI振荡 | 相位裕度不足 | 降低带宽、加延迟补偿 |
| 中断超时 | 算力不够 | 优化代码、降PWM频率 |
| 低速采样不准 | 纹波影响 | 改DSSU、加模拟滤波 |
9. 几个容易被忽略的细节
9.1 死区时间对延迟的隐性贡献
死区时间本身不直接增加电流环延迟,但它会引入电压误差,导致电流过零附近波形畸变。在DSDU下,死区误差会被双采样放大。我通常会在SVPWM里加入死区补偿,根据电流方向修正占空比。
9.2 母线电压波动的影响
母线电压波动会影响电流响应速度。在高带宽下,母线电压的采样和补偿必须跟上。我见过一个项目,电流环带宽做到1.5kHz,但母线电压采样只有1kHz,结果动态响应被母线电压延迟拖累了。
9.3 温度对采样精度的影响
霍尔传感器的零漂和增益随温度变化,长时间运行后采样精度会下降。DSSU的双采样平均能部分抵消零漂,但不能解决增益变化。高精度场合建议用分流电阻采样,配合温度补偿。
9.4 代码优化的小技巧
FOC计算里,Park变换的sin/cos查表比实时计算快得多。SVPWM的扇区判断可以用条件判断替代查表。PI控制器的积分限幅要放在输出限幅之前。这些细节在DSDU下尤其重要,因为计算时间直接吃掉延迟余量。
10. 我的实际选型建议
如果你刚开始做FOC,别一上来就追求DSDU。先用SSSU把整个链路跑通,理解采样、计算、更新的时序关系,再逐步优化。SSSU虽然带宽低,但胜在稳定、易调试,适合入门。
当你需要更高带宽时,优先考虑SSDU。它只需要算一次FOC,对MCU算力要求不高,延迟又比SSSU小。很多国产MCU(比如峰岹的某些型号)在SSDU下表现就不错。
DSDU是性能天花板,但也是坑最多的。双采样带来的噪声不对称、计算时间紧张、中断优先级冲突,每一个都可能让你调几天。我建议只有在确实需要2kHz以上带宽时才上DSDU,并且一定要留足算力余量。
DSSU适合那些对电流精度要求高、但对带宽要求不极致的场景。低速直驱、力矩控制、精密测量这些场合,DSSU的双采样平均能给你更干净的电流信号。
最后再分享一个小技巧:不管用哪种策略,都建议在代码里加一个"延迟测量"功能。用一个GPIO在采样时刻翻转,在更新时刻再翻转,用示波器量脉冲宽度,你就能精确知道自己的实际延迟是多少。这个数据比任何理论计算都可靠,也是调PI参数时的重要参考。