我调第一版无感FOC零速启动的时候,差不多折腾了两周。高频注入的波形明明已经叠上了,解调出来的角度也能跟着转子走,可是一带负载就飘,而且飘得很有规律,不是随机噪声那种。后来对着示波器和调试变量一帧一帧查,才发现根子根本不在PLL带宽,而在最基础的那几个频率关系上:中断里跑的电流环频率、注入信号的频率,以及Ud/Uq这个电压指令里低频PI输出和高频分量之间的比例——我之前全把它们当成两个孤立参数在调。
这个标题里列的三样东西,Ud/Uq(论文里常写成U_d/U_q,代码里对应ud_pi、uq_set之类的变量)、控制频率、HFI注入频率,其实是同一条链路。主中断里电流环跑多少赫兹,决定了你能把注入频率放在哪个位置,也决定了解调环路的时基落在哪里;而Ud/Uq作为电流环PI的输出、逆变器端电压的参考、以及高频注入信号的载体,把时域和频域整个串在了一起。很多人做无感FOC卡在低速段,不是算法原理哪里不懂,而是这三者的关系一直没理顺。
这篇文章我就把这条链路从头到尾掰开讲,重点是每个参数背后的取舍逻辑,而不是只给一组能用的数值。适合正在调无感FOC低速启动、或者刚准备把高频注入真正算进中断时序里的工程师参考。看完你大概能回答这几个问题:控制频率到底是谁定的?Ud/Uq测出来为什么和理论不一样?注入频率为什么落在PWM频率的十分之一附近而不是越高越好?
1. 频率到底归谁管:PWM、采样、控制中断绑在同一条时间线上
1.1 主中断是谁触发的,控制频率是怎么定下来的
先破除一个最常见的误解:控制频率不是“算法想跑多少跑多少”,在绝大多数单MCU数字FOC方案里,控制频率、电流环中断频率、PWM载波频率三者是绑定的。用STM32举例,高级定时器TIM1/TIM8产生中心对齐的对称PWM,载波周期就是PWM周期。定时器在下溢或溢出时通过硬件触发ADC采样,ADC转换完成后再触发中断进入FOC主循环。这条链是:PWM波形生成 → 触发采样 → ADC转换完成中断 → 电流环执行 → 更新比较寄存器,一个周期闭环跑完。所以PWM周期是多少,电流环就跑多少,20kHz PWM对应的就是20kHz控制频率。
为什么要绑在一起?因为电流环必须知道“本PWM周期里实际流过电机绕组的电流”,才能计算下一周期的占空比。绑在一起意味着采样时刻、计算时刻、PWM更新时刻全部对齐,PI控制器的相位延迟最小。如果让控制循环脱离PWM事件、用单独一个定时器自由跑,会出现一个不确定的“采样到更新”的延迟,这个延迟直接进电流环的开环传递函数,电流环带宽做到一定值以上必然振荡。我见过一个项目为了省事,把FOC主循环放在主程序while里跑,结果电流环带宽连额定的一半都扛不住,就是吃了这个亏。
1.2 采样时刻为什么必须“卡”在PWM周期中心
电流采样的时刻选择非常讲究,理论上是为了避开三件事:死区、开关噪声、以及占空比极端时采样窗口不够的问题。对称PWM在下桥臂导通中点附近,逆变器输出正好等于三相平均电平,相电流的di/dt相对平稳,ADC采出来的样本最有代表性。这就是为什么STM32的ADC注入触发要配置在定时器周期中点的原因。
一个有信息量的经验:采样点一旦抖动,电流噪声会直接进PI,最后体现在Ud/Uq指令上就是高频毛刺。你可以做一个简单实验——把ADC采样由软件触发改成硬件触发,其他代码不变,观察ud_pi变量的波动幅度,通常会有立竿见影的改善。这也是为什么我后来只要看到电流波形“莫名其妙地吵”,第一件事先查采样触发配置,而不是去调PI增益。
1.3 控制频率不等于所有环路的执行频率
不少人把“控制频率”当成一个单一概念,实际工程里是要拆开问的:是电流环频率?是速度环频率?还是高频注入解调环路的频率?这三者之间往往差一个数量级。
电流环和PWM绑定,一般是10kHz或者20kHz。速度环没必要每50μs跑一次,常见做法是给电流环做整数分频,比如每20个PWM周期执行一次速度环,算下来就是1kHz。高频注入解调更特殊:它的带宽需求不高,但计算量不小,后面我会专门讲怎么把解调环路放到慢速时基里。所以当你和别人讨论“FOC控制频率”的时候,一定要先明确说的是哪一级环路,否则所有参数讨论都是鸡同鸭讲。
2. 分清三份Ud/Uq:PI指令、逆变器实际输出、观测器的“印象”
2.1 先分清三份“Ud/Uq”再谈波形对不对
日常调试中,Ud/Uq这个符号至少对应三种性质完全不同的东西,很多人把三者混在一起,就产生了“Ud/Uq怎么都不对”的困惑。
第一份是电流环PI计算出来的电压指令,这是控制器唯一直接算出来的量,软件变量里直接能读到,通常叫ud_pi、uq_pi。第二份是真正出现在电机端口的电压对应的dq分量,它要经过反Park、SVPWM、死区、功率管压降、母线电压波动一系列环节,和指令值并不相等。第三份是观测器内部重构出来的电压/反电动势量,滑膜观测器和磁链估计器实际上都在拿第一份值当输入,然后估算出转子位置。
调试时要说“Ud/Uq不对”,90%的情况是指第一份和第二份之间产生了偏差,而这个偏差会引发连锁反应:死区导致第二份实际值总比第一份小一点,无感观测器不知道这些开关损耗,会把误差误当成反电动势的一部分,于是低速下角度就被“拽”偏了。这也是为什么低速无感FOC对死区补偿特别敏感。
2.2 稳态下Ud/Uq长什么样,怎么从波形判断系统状态
假设表贴式PMSM且采用id=0控制,稳态下的d轴电压指令大致等于电阻压降加上一个与转速成正比的交叉耦合项,数值很小;q轴电压则承担绝大多数输出,包括电阻压降、速度项和反电动势项。所以在正常带载运行时,Uq比Ud大得明显,负载加大时Uq同步变大,高速弱磁之后Ud会更快地往负方向偏移。这是判断系统状态的一个很直观的窗口。
实操建议:不要只盯着电流环增益看,把ud_pi、uq_pi录进虚拟示波器,跑一个完整的加减速和加载流程,你会对电机在不同工况下的电压需求有直观认识。我后来排查过一台电机高速啸叫的问题,就是发现Uq波形在高速段出现明显的饱和平顶,才知道是电压裕量不足导致的。这种问题不看Ud/Uq趋势单靠听声音,很难定位。
2.3 高频注入时Ud/Uq多出来的是什么
零速高频注入时,我们会在估计d轴的电压指令上叠加一个高频余弦电压(后面第三部分详述)。这时候第一份Ud/Uq的波形就变成:低频PI输出叠加上高频余弦载波。
第一次看到这个波形很容易慌,因为注入幅值可能比PI输出本身还大,示波器上Ud看起来像失控振荡。这时候不要急着怀疑算法,先做两件事:一是确认该高频分量的频率是不是你设置的注入频率,二是看幅值是否稳定。我用软件FFT看频域幅度,比直接看时域波形可靠得多。一个常见误区是把示波器低通滤波打开,把高频分量滤掉再看“干净的Ud”,这样会丢掉关键信息——你正需要确认那个高频分量确实送到了电压指令里。
3. 高频注入的频率不是拍脑袋定的:从电流环频率反推注入频率
3.1 为什么零速非要用高频注入
无感FOC在零速和极低速时反电动势几乎为零,滑膜观测器、龙伯格观测器、扩展卡尔曼滤波全都没信号可用。这时候必须换一个物理量来利用:电机自身的凸极性。内嵌式IPM电机的d/q轴电感不等,表贴式SPM则利用磁路饱和引起的非线性凸极。往电机里注入一个电压信号,电流响应里就会携带转子位置信息。高频注入就是基于这个思路。
具体到工程实现,最常用的是脉振高频电压注入法:在估计的旋转坐标系d轴上注入一个高频余弦电压,然后在q轴电流里解调出位置误差信号。它的信噪比好坏,很大程度上取决于注入频率选得对不对。
3.2 脉振注入的信号链路简述
为了讲清楚频率约束,先快速过一遍信号链路。在估计d轴注入u_dh = Vm * cos(2π f_inj t)之后,电机会在一个稍偏的位置上被激励,dq轴的高频电流响应里就带上了转子位置误差信息,尤其q轴高频电流的幅值在小误差角时近似正比于位置误差。接下来用带通滤波器把q轴电流里的注入频率分量提取出来,乘以同频的余弦信号做同步解调,再过一个低通滤波器,得到误差信号,最后进PLL或PI修正估计角度。
这套链路里,带通滤器、同步解调、低通滤波器都需要一定的时间窗去工作,数字控制器里它们靠的是离散采样点。这就决定了注入频率和电流环采样频率之间必须满足一个基本关系。
3.3 注入频率选择的核心约束
最重要的约束:每个注入周期至少要覆盖5到10个电流环采样点。20kHz电流环配1kHz注入,一个周期有20个采样点,非常从容;10kHz电流环如果还选2kHz,一个周期只剩5个点,数字解调的波形分辨率就开始恶化。经验上注入频率取PWM/控制频率的1/10到1/5是常用区间,具体要看MCU负担和硬件滤波。
其他的约束还包含:
- 注入频率必须高于速度环带宽和观测器闭环带宽的3到5倍,否则注入信号和转速动态混在一起很难分离。速度环带宽30Hz时,注入频率几百赫兹以上起步就已经合理,不要往100Hz以下选。
- 必须避开电流采样调理电路上RC低通的截止频率。如果前置低通截止在1.6kHz,注入频率选2kHz,高频电流响应会被硬件衰减掉一截,解调信噪比骤然变差。
- 避开功率级LC谐振点,比如母线电容和电机绕组电感构成的谐振频率。这条很多人忽略,实际影响可能很大。
实在拿不准的时候,做一个“注入频率小扫频”:在估计d轴上用固定幅值注入几个不同频率,逐个记录q轴高频电流响应幅值,选择响应最大且噪声最小的那个频率作为注入频率。这个测试半小时就能做完,比翻手册猜参数靠谱得多。
3.4 注入幅值也是要一起算的
注入幅值通常给到母线电压的5%到12%。表贴式SPM因为凸极率小,主要靠饱和凸极,幅值往往要比IPM给得更大;但也不是越大越好,幅值太大会占掉PI输出的电压余量,同时带来明显的电机啸叫和额外损耗。
实操上我会先从母线电压的8%起调,看解调误差信号的信噪比再加减。幅值单位换算容易出错,尤其标幺化系统里,记得先确认基准电压是多少V,再把标幺系数换算回实际伏特数。我见过一个团队把0.08当成8%直接用,结果实际注入只有一点点,解调自然做不通。
4. 中断时序与解调任务分工:注入电压加在哪一步,PLL环放谁家
4.1 FOC主中断的时间预算先算清楚
一个标准的电流环——ADC读取、标幺、Clarke/Park变换、两个电流PI、反Park、SVPWM——在常见MCU上大概要占10到20μs的级别。20kHz对应50μs一个周期,主中断占用率已经不低。如果还要在这个中断里顺手完成高频注入的带通滤波、解调乘积、低通滤波和PLL,预算会非常紧。
我的习惯是先用GPIO翻转法实测中断执行时间:进中断置高,出中断置低,用示波器看高电平宽度,就知道当前占用率。然后再决定解调环路是留在主中断里,还是拆到慢速时基。这一步的重要性不亚于算法本身,尤其当后续还要叠加滑膜观测器、速度环、弱磁策略时,预留时间裕量是必须的。
4.2 解调环路的两种落法:全塞主中断,还是放进慢速时基
第一种方案是把解调全部放在主中断里。好处是每个PWM周期拿到的dq电流都是最新的,解调延迟最小,理论上动态响应最好。代价是计算量大,在低端MCU上很可能超标,而且代码里塞进大量浮点滤波会让整个中断变得又长又脆。
第二种方案是主中断只做“轻活”:叠加注入电压、保留原始dq电流的历史样本;把带通滤波、同步解调、低通滤波、PLL放到一个较慢时基的中断里。比如20kHz主中断下,用LPTIM或SysTick开一个1kHz左右的慢速中断专门处理解调。代价是解调链路的更新延迟从50μs级别变成1ms级别,但低速工况下位置环带宽本来就不高,这个延迟完全能接受。
我工程上的习惯:先把功能全部放在主中断里跑通,确认算法和参数正确;然后再把解调环移入慢速时基,移的时候要保留滤波器历史状态而不是直接清零,否则切换瞬间会出现相位跳变。两种方案的边界取决于你的MCU主频、电流环代码优化程度,以及项目后续还要叠加多少功能。
4.3 注入电压加在哪一步,决定它能不能“活着”到电机端
这个坑我踩过一次之后印象很深:如果把高频注入信号加在电流环的参考电流上,PI控制器会把它当成低频误差的干扰去“压制”,高频分量被积分器吃掉大半,最终到达SVPWM的注入电压所剩无几。正确做法是把注入电压直接叠加在电流环PI输出的ud_pi和uq_pi上,然后再进行反Park变换。因为反Park之后虽然换了参考轴,但信号频率不变,注入分量才能原样进入SVPWM最终加到电机端口。
伪代码大概是这样的:
// FOC主中断,PWM周期50us @20kHz void foc_isr(void) { adc_read_and_scale(); // 读三相电流并标幺 clarke_park(); // 电流变换到dq同步坐标系 pi_controller_id(); // d轴电流环 pi_controller_iq(); // q轴电流环 // 高频注入叠加在电压指令上,不是加在电流参考上 u_d_inj = ud_pi + Vm * cosf(2.0f * PI * f_inj * t_phase); u_q_inj = uq_pi; inv_park_and_svpwm(); // 反Park + SVPWM,更新比较寄存器 t_phase += t_step; // 更新注入信号相位 }另一个关键时序细节:注入相位t_phase的更新必须和PWM周期严格同步,否则注入波形会出现相位漂移,解调出来的误差信号会带上低频抖动。最简单的方式就是像上面一样,每个PWM中断累加固定步长,并且在配置时保证步长对应的频率精度足够。
4.4 中断优先级分配与磁极方向判别
如果项目里还有通讯中断、编码器Z相信号、网口同步中断之类的东西,优先级分配要非常明确:电流环主中断最高,高频解调慢速中断次之,通讯这类容易丢但延迟不敏感的功能放最低。实际故障案例里,一帧串口数据打断了一次电流环,角度就开始抖;把优先级调对之后,同样的参数不再发飘。这个优先级表应该出现在项目设计文档的第一页,而不是等到出问题了再补。
最后补一个高频注入特有的麻烦:脉振高频注入解调出的角度在电角度周期内存在180度模糊,也就是无法区分N极和S极。初始位置检测时还需要额外做磁极极性判别,常见做法是在估计d轴再施加正向和反向短时电压脉冲,比较dq轴电流响应中的饱和差异;或用注入信号中的倍频分量来判定极性。这一步不做,电机上电启动就可能在反方向上“打嗝”,表现为起步瞬间先倒转一小段再恢复正常。
5. 实测参数、三个典型坑与低速到中速的观测器衔接
5.1 一组能直接参考的参数配置
下面是一台中等功率低压表贴式电机的参考配置,供电48V,额定功率350W,极对数4。这套参数是从实际项目里整理出来的,可以作为起点,但不建议原封不动照搬——电机本体和硬件滤波不同,最优值一定会有偏移。
| 参数 | 推荐值 | 备注 |
|---|---|---|
| PWM/控制频率 | 20kHz | 电流环与PWM绑定,中心对齐 |
| HFI注入频率 | 1kHz | 约为控制频率的1/20,每周期20个采样点 |
| 注入幅值 | 约5V | 母线48V的10%左右,表贴式按信噪比上调 |
| 带通滤波器中心频率 | 1kHz | 带宽±100~200Hz,提取q轴高频电流 |
| 解调低通截止 | 200Hz | 保留位置跟踪动态,滤除二倍频分量 |
| 位置PLL带宽 | 20~30Hz | 先低后高,观察角度噪声收敛 |
| 速度环频率 | 1kHz | 电流环20分频 |
| 电流采样触发 | PWM中心对齐触发ADC | 硬件触发,避免软件偏移 |
5.2 我踩过的三个具体坑
第一个坑是注入频率撞上采样滤波。我第一次调一个10kHz PWM的板子,按习惯把注入频率设到2kHz,结果解调误差信号像混了锯齿的白噪声。查到最后发现采样运放前面RC低通的截止频率大概只有1.5kHz,2kHz的高频电流响应被硬件削掉了大半。把RC截止提到3kHz以上,同时把注入降到1kHz,信号一下就干净了。这件事给我的教训是:先看硬件滤波瓶颈,再选注入频率,顺序不能反。
第二个坑是PLL带宽拔太高。为了追求“跟手”,我把初始位置收敛和启动时的PLL带宽调到80Hz,结果角度噪声变大,带载时中频分量漏进位置环。后来改成20Hz起步,逐台往上试,找到噪声和动态需求的交界点。位置环这种地方,不是越快越好,要看你前端的解调信号质量。
第三个坑是解调滤波代码留在主中断里导致时间超限。那版程序在主中断里放了浮点带通加低通,中断执行时间抖动变大,PWM更新时刻后移,电流采样也跟着抖动,电流环整个变吵。把解调挪到1kHz的慢速时基中断之后,同样的算法参数下电流噪声立刻下来了。这个经验在低成本MCU上尤其重要。
5.3 从HFI过渡到滑膜观测器时,衔接要平滑
启动和极低速用HFI,转速起来之后要切换回滑膜或磁链观测器。切换点一般设在额定转速的5%到10%之间。我的做法是:在预定切换转速之前就开始同时运行两套观测器,但只让HFI参与闭环;等两者估计的角度差小于一个阈值(比如5度)并持续几百毫秒后,再做一次平滑交接。
交接的细节上,要把HFI的PLL输出角度做2π取余,滑膜观测器的估计角度在交接前也初始化到同一值,避免切换瞬间的跳变。速度环这边,给速度指令加一个斜坡限制,避免切换造成的速度扰动。很多项目在切换点出现“咯噔”一下的顿挫感,基本都是因为两边角度没有提前对齐,直接硬切。这个提前运行、角度对齐、斜坡过渡的三步流程,比任何花哨的加权融合都实用。
我个人后来每做一个新平台,都会先建一张频率和时序对照表,把PWM频率、采样时刻、电流环中断、解调时基、速度环分频数全部写清楚,再动手写代码。那张表花不了几分钟,但省下来的调试时间通常是几倍起步。那次“高频注入角度飘两周”经历之后,这个习惯就一直保留下来了。