☰
无感FOC零低速方案:高频注入HFI位置观测链路详解
2026/10/1 1:29:25 网站建设 项目流程

做无感FOC的兄弟,应该都见过这种场面:低速负载转得好好的,突然换个方向起动,电机咔咔响两下,控制器直接报过流。很多情况下,问题就出在低速位置观测失效。常规反电动势观测器在零低速下基本“看不见”,所以工程上要上高频注入(HFI)、IIR滤波、位置估计和磁极极性判断这一整套组合。这篇文章我把自己调高频注入无感FOC的完整思路讲清楚,包括高频电压怎么叠加、电流信号怎么过滤、位置环怎么收敛、磁极极性怎么判,以及实机上踩过的坑。如果你也在看HFI代码但总觉得隔着一层,这篇应该能帮你把链路彻底理顺。


1. 为什么零低速无感FOC绕不开高频注入

1.1 反电动势在低速下“消失”,滑模观测器吃不消

永磁同步电机的反电动势与转速直接成正比:转速越低,反电动势越小。低速甚至零速的时候,反电动势小到被电流采样噪声、逆变器死区误差、母线电压波动完全淹没。滑模观测器这类基于反电动势的位置观测器,本质上是在“放大”反电动势信号来提取位置,信号都没了,增益再大也只是把噪声一起放大,观测角度就会飘,甚至抖得没法闭环。

所以业界的完整做法通常是两台观测器协同工作:中高速靠滑模观测器(很多人写成滑膜观测器)或者龙伯格观测器,零低速靠高频注入。把这两段拼起来,才能覆盖从零速到高速的整个调速范围。

1.2 HFI的核心:凸极率才是“眼睛”

高频注入能工作的物理基础是电机的凸极效应。永磁电机的d轴和q轴磁路阻抗不同,转子直轴和交轴的电感也不一样,整个电机从定子看过去就像一个随转子角度旋转的椭圆。在定子上加高频电压,产生的电流幅值、相位就会跟着转子角度变化。转子转不转都无所谓,电感特性就在那里,所以即使电机完全停住,高频响应里也藏着位置信息。

生活里可以类比成一个带椭圆截面的橡皮管:你用固定力度从不同方向去捏它,变形程度不同。电机也是一样,高频电压加在不同方向上,电流响应不一样,这个不一样就暴露了转子方向。

1.3 HFI不是银弹,它的边界在哪

高频注入的代价也很明显:高频电流会带来额外铜耗和铁耗,电机啸叫变明显;注入电压还会占用母线电压余量,重载高速时会被 PWM 限幅吃掉。另外如果电机凸极率太低,比如部分表贴式电机,位置信号本身就弱,HFI 会很难锁定。工程上一般只在零到额定转速的 5%~10% 这个区间用 HFI,过了这个速度还是切回反电动势观测器更稳。

我当时接手项目第一步,先做了一个“转速-观测器选择表”,把每个转速段的控制策略定死,后面调试少走很多弯路。

2. 高频注入信号设计:频率、幅值和叠加位置

2.1 脉振注入和旋转注入怎么选

高频注入实现上有两大流派:旋转高频电压注入和脉振高频电压注入。

旋转注入是把高频电压矢量和角度无关地在αβ静止坐标系里转,位置信息藏在负序高频电流里,理论上对各种电机都适用。脉振注入是在估计出来的d轴电压上,叠加一个高频余弦(或正弦)分量,误差信号从q轴高频电流里解调出来。脉振注入实现更简单,代码量小,而且对表贴式电机的低凸极率场景反而更容易调出信号,工业无感FOC里最常见的也是它。

我自己做样板的第一版选了脉振注入,原因很实际:调试时只需要盯一路解调误差,遇到问题更容易定位。

对比项旋转高频注入脉振高频注入
注入位置αβ静止坐标估计d轴
信号提取负序分量q轴高频分量
位置误差形态近似2倍角度误差近似sin(2Δθ)
实现复杂度中低
低凸极率电机信号较弱相对更好使

2.2 频率与幅值怎么定,才能既出信号又不吵

注入频率的选取要同时躲开三个限制:电流环带宽、采样频率、PWM开关频率。

电流环带宽一般几百赫兹,注入频率如果低于电流环带宽,叠加在电压上的高频分量会被电流环控制器当作干扰给压掉。注入频率还得低于电流采样频率的奈奎斯特频率,否则高频信号直接混叠到低频段,带通滤波器也救不回来。工程上常用开关频率的 1/8~1/4。10kHz PWM 的板子,注入频率用 1kHz 起步,我实测下来兼顾了解调信噪比和噪声表现。

幅值方面,目标是让高频电流峰值大约达到额定电流的 5%~15%。母线电压越充裕,幅值可以越小;母线电压紧张,就只能靠加大幅值把信号从噪声里顶出来。我调试时习惯先给一个偏大的幅值,确认解调误差波形正常,然后再慢慢降幅值,一直到噪声冒头再往上回调一点。

2.3 代码上,高频电压到底叠加在哪一层

一个常见的错误是往电流环给定值上叠高频电压。电流环带宽有限,很可能把这个高频分量当成扰动吃掉,导致你注入了一大半电压,最后电机侧实际响应很小,相位还乱。我更推荐直接叠加在电流环输出电压上,绕过反馈回路的衰减。代码结构大概是这样的:

void current_ctrl_isr(void) { // 高频相位累加,运行周期固定 theta_hf += HFI_OMEGA * ISR_PERIOD; // d轴脉振高频注入,叠加在PID输出电压上 vd_ref = vd_pid_out + HFI_AMP * cosf(theta_hf); vq_ref = vq_pid_out; // 后面正常做Park反变换、空间矢量调制 }

注意一个问题:高频注入会让电压指令带上高频成分,如果此时电流环PID还没稳定,很容易触发过流或电压饱和。启动初期应该把注入幅值按斜坡逐渐加上去,不要一开机就给满幅值,否则很容易听“啪”一声然后报母线过流。

3. 高频响应提取:IIR滤波器设计和位置误差解调

3.1 从电流环里提取位置误差信号的完整通路

这部分是整个HFI的灵魂。以脉振注入为例,完整信号链路是:

  1. 采样三相电流,做Clarke变换和Park变换,得到估计dq坐标系下的id_est和iq_est。
  2. 用带通滤波器从iq_est里提取高频电流分量iq_hf。
  3. 将iq_hf与高频注入的参考信号相乘,得到包含低频误差分量的解调信号。
  4. 再用低通滤波器把2倍高频载波分量滤掉,剩下的直流分量就是位置误差信号。

这里最关键的坑是解调参考相位。电感电流比电感电压滞后90度,如果你的注入电压是cos(ωh·t),那么高频响应电流的相位就会偏向sin(ωh·t)。所以解调时如果机械地用cos参考相乘,误差信号会被削掉,PLL根本锁不住。要把参考信号跟着实际电压波形的相位统一起来。

float iq_hf = bandpass_iir_q(iq_est); // 注入电压使用 cosf(theta_hf),响应电流近似 sinf(theta_hf) float demod = iq_hf * 2.0f * sinf(theta_hf); float err_pos = lowpass_iir_demod(demod);

这条链路里每一段滤波都直接影响最终角度质量。我调试时习惯把iq_hf和err_pos分别通过DAC或调试口引出来看波形,先用肉眼确认“手转电机时误差波形会随转角变化”,再谈闭环。

3.2 二阶IIR带通滤波器:系数和实现

MCU上最常用的是二阶IIR滤波器,也叫Biquad。它计算量小,一个周期几条乘加指令就完成,而且系数设计方法成熟。

typedef struct { float b0, b1, b2, a1, a2; float x1, x2, y1, y2; } IIR2; float iir2_run(IIR2 *f, float x) { float y = f->b0 * x + f->b1 * f->x1 + f->b2 * f->x2 - f->a1 * f->y1 - f->a2 * f->y2; f->x2 = f->x1; f->x1 = x; f->y2 = f->y1; f->y1 = y; return y; }

对于中心频率为fc的带通滤波器,在采样率fs下,Q值设定好后系数可以这样算:

float omega = 2.0f * PI * fc / fs; float alpha = sinf(omega) / (2.0f * Q); float a0 = 1.0f + alpha; float b0 = alpha / a0; float b1 = 0.0f; float b2 = -alpha / a0; float a1 = -2.0f * cosf(omega) / a0; float a2 = (1.0f - alpha) / a0;

Q值直接决定带通宽度和滤波器的相位特性。Q值取1左右时,通带比较宽,相位延迟适中,最适合初期调试。Q值取到5甚至更高,通带变窄,选择性变好,但相位延迟也跟着变大,解调误差一路积下来,PLL的稳定裕度会被吃掉。见过很多代码把Q值抄成10,结果电机零速锁不住还以为是增益问题,实际上是被滤波器相位坑了。

3.3 滤波器的“相位账”必须提前算

HFI链路里至少有两个滤波器:带通滤高频电流、低通滤解调后的直流。加上PLL本身的积分延迟,整个环路等效成了一个高阶系统。滤波器相位延迟太大的时候,你看到的误差信号已经滞后于真实位置误差,PLL会把滞后的信号当作真实误差去收敛,结果就是收敛到错误位置或持续振荡。

我调参数有个习惯:解调低通的截止频率至少放到PLL带宽的3~5倍,比如PLL带宽30Hz,低通截止可以放到100Hz左右。带通滤波器的中心频率不要偏离注入频率,否则高频信号本身就被削弱,后面的低通再猛也没用。

调试时先把滤波器的幅频曲线、相频曲线拉出来看一眼。IIR滤波曲线这玩意儿不亲眼看一遍,光靠猜系数永远调不透。一个简单办法是在代码里把滤波器单独导出成Bode图比对,确认中心频率增益和相位延迟在预期范围内。

4. 位置估计和磁极极性判断:让角度真正可用

4.1 用PLL收敛位置误差,而不是硬解反正切

解调出来的误差信号,在估计角度和真实角度差Δθ不大的时候近似正比于sin(2Δθ)。直接对这个误差取反正切也能得到角度,但噪声会被放得很大。工程上更常用PLL结构,让PI控制器把这个误差压到接近零,同时输出转速和角度。

typedef struct { float integrator; float speed; float theta; } HFI_PLL; void hfi_pll_update(HFI_PLL *pll, float err, float dt) { pll->integrator += err * dt; pll->speed += (pll->kp * err + pll->ki * pll->integrator) * dt; pll->theta += pll->speed * dt; angle_wrap(&pll->theta); }

PLL带宽不能设太高。低速下位置误差信噪比有限,带宽太高会把噪声带进来,电机表现为零速附近抖动。我自己的调参顺序是:先把Ki设成Kp的十分之一左右,然后Kp从很小开始往上加,每次加完用手堵住轴观察抖动,一旦发抖就退回上一档再折半。Kp和Ki最终要在带载起动场景下再微调,空载调出来的参数经常不够用。

这里还有一个容易忽视的符号问题。误差信号到底该加正号还是负号,取决于你的坐标变换方向、Park变换角度定义和解调参考相位。如果PLL的误差符号反了,观测器会把角度往反方向推,结果就是永远锁不住。先在开环模式下用手转动转子,看误差波形,再决定代码里要不要加负号。

4.2 磁极极性判断:只做HFI不判极性,起动必反转

高频注入只能把转子位置锁定到0度和180度中的一个,因为d轴正方向和反方向的电感特性一样,位置误差是sin(2Δθ),周期是180度。但真实转子只有一个磁极方向,如果不判N/S,上电直接有50%概率找到那个反方向,电机一转就倒转。

N/S的区分要靠磁饱和效应。转子永久磁场的d轴方向和电流产生的磁场方向一致时,磁路更容易饱和,电感变小;方向相反时,磁路饱和度低,电感变大。工程上最常用的方法是正负电压脉冲响应比较法。步骤是:

  1. 先用HFI把角度收敛到某一个方向θ0。
  2. 断开电流环或保持开环,沿估计d轴施加一个正电压脉冲,持续0.5到1毫秒,在脉冲结束前采样id_plus。
  3. 停一段时间,等电流衰减到零。
  4. 沿同一个d轴方向施加负电压脉冲,采样id_minus。
  5. 比较两个电流绝对值,如果|id_plus|明显小于|id_minus|,说明HFI收敛的方向是反的,把角度加180度。
if (fabsf(id_plus) < fabsf(id_minus)) { theta_est += PI; }

为什么电流大的那个方向就是N极方向?因为正d轴电流让磁路更饱和,电感变小,同样电压下电流上升更快,最终电流幅值更大。方向对不上时电流就小。极性确认不能只测一次,我是连续测三次取多数结果,避免脉冲期间干扰导致误判。电流脉冲的幅值不宜过大,否则可能退磁,尤其是磁钢矫顽力裕量小的电机。

4.3 极性判断的时序和常见失误

极性判断时序最怕电机还没稳定就采样。脉冲加上去以后电流有一个建立过程,采样点太早读到的是电感电流的暂态而非饱和差异,太晚PWM都快结束了,读到的可能已经是续流阶段的值。我通常是先让电流建立大约0.3到0.5毫秒以后再采样,采样点放在ADC同步触发时刻,保证每次采样的电气角度一致。

另一个坑是正负脉冲之间没有留死区时间。电流没完全回零就发反向脉冲,相当于给电机加了两次连续的冲激,位置可能被冲偏。极性测试期间输出轴会有一点微动,负载较大的系统还要考虑机械执行的间隙影响,重复多次中有一次明显偏掉时,直接丢弃该次结果重测。

5. 实机调试中的高频注入问题排查

5.1 常见现象与处理办法

现象可能原因处理办法
角度一直飘,锁不住解调参考相位错把sin/cos参考互换测试
锁在错误位置,低速抖动滤波相位延迟过大降低带通Q值,提高解调低通截止频率
电机啸叫明显发热注入幅值过大按额定电流5%目标回降幅值
起动方向时对时反磁极极性判断不充分多次测量取多数,检查死区时间
从HFI切到滑模时跳动两套估计角度和速度没同步并行运行两个观测器,加过渡带混合
电压利用率不够注入频率接近电流环带宽提高注入频率或减小注入幅值

5.2 参数调试的推荐顺序

不要一上电就闭环绕。我习惯按下面四步走:

第一步,开环模式注入,手动转动转子,观察高频电流的包络是否随转角变化。这步可以确认HFI信号本身是否存在于电流采样里。

第二步,打开解调低通,把手转的误差信号接到调试口,看它是否随转角呈正弦变化。如果这步波形不对,后面调PLL全是白费。

第三步,打开PLL观测器,堵住轴停在某位置,确认估计角度稳定。然后缓慢转动转子,观察估计角度是否在0到2π之间连续变化,特别要注意有没有180度跳变。

第四步,做极性判断,确认角度方向正确,再进入闭环起动。闭环以后先空载,再逐步加负载。每次改完参数不要急着连电机,先看误差波形再上系统。

5.3 一个容易翻车的细节:电流采样时刻

高频注入对电流采样同步性要求非常高。PWM载波不同时刻采样,注入信号在采样点上的投影值不一样,解调出来的误差会带一个跟转速相关的小波动。我建议把ADC采样触发放在PWM载波的固定点,比如三角载波顶点或底点,并且让注入相位的累加跟PWM中断对齐。多轴系统如果几个电机共用一块MCU,每个电机的高频相位要分开累加,不要共用同一个theta_hf。

另外,采样电阻噪声太大会直接把高频信号淹掉。实机上那个“零速锁不住”的故障,有一大半其实不是算法问题,而是电流采样地线布局不好。调试时把示波器探头别夹在功率地附近,探头地线尽量短,能避免很多假象。

6. 把整条链路串起来:一个可参考的启动流程

6.1 带HFI的无感FOC启动状态机

实际项目里我不会一上来就把HFI和磁极极性判断全部打成一个大函数,而是按状态拆开。每个状态的退出条件都很明确:

  1. HFI对齐阶段:运行PLL观测器,让估计角度收敛到某个候选方向,退出条件是角度波动小于一定阈值持续若干毫秒。
  2. 极性判断阶段:执行正负脉冲测试,根据结果修正角度,退出条件是得到一致的结果。
  3. 带载起动阶段:保持HFI闭环,电流环给一个较小的d轴电流或转速斜坡,让电机平稳转起来。
  4. 切换阶段:转速超过设定阈值后,将滑模观测器或反电动势观测器逐渐接入,HFI逐渐退到后台。

状态机不要跳着来,特别不要在极性判断没完成时直接进闭环。我见过一次为了省事把极性判断和HFI启动合并,结果负载齿轮间隙大,极性判断时轴被顶偏,反了180度进闭环,整个系统当场过流。

6.2 简化的HFI主流程伪代码

下面的代码只是展示链路关系,不是可以直接编译的完整项目。实际使用时需要把每个函数都替成你自己板子上调好的滤波器和观测器。

typedef struct { float theta_est; float speed_est; uint8_t polar_done; } FocRotorEst; typedef struct { IIR2 bp_q; IIR2 lp_demod; HFI_PLL pll; } HfiParam; void hfi_task(HfiParam *hfi, FocRotorEst *est, float iq_est, float dt) { float iq_hf = iir2_run(&hfi->bp_q, iq_est); float demod = iq_hf * 2.0f * sinf(theta_hf); float err_raw = iir2_run(&hfi->lp_demod, demod); hfi_pll_update(&hfi->pll, err_raw, dt); est->theta_est = hfi->pll.theta; est->speed_est = hfi->pll.speed; }

6.3 集成时最容易忽略的初始化问题

每个IIR滤波器的状态变量在启动时必须清零,但不要在每次中断里清零。很多人把滤波器初始化和PWM中断放在一起,结果每次进中断状态都被重置,电流永远带通不出来。

如果使用固定点芯片,IIR系数需要先缩放到Q格式,避免溢出。尤其是b0和b2是一正一负,定点实现时中间累加顺序不同会引入额外误差。检查方法很简单:给滤波器一个固定频率正弦波,打印输出看幅值是否等于理论增益,如果偏了再检查定点缩放。

启动流程中还要把PLL积分项清零,否则上一次停机时的角度误差会残留到下一次起动。尤其是电机被外力拖着转过的场景,不清积分直接起动,那一下能顶掉半个系统。

做完整套高频注入链路以后,我的体会是:真正难的不是某个公式或某段代码,而是每条信号链路上的相位和时序都对得上。滤波器系数抄来很快,但解调参考相位、采样时刻、PLL符号这些“软细节”才是决定能不能锁住的关键。最后再分享一个小技巧:调试HFI时,给控制板留一个DAC输出通道,专门用来观察误差信号。肉眼看到正弦波形的瞬间,比你在示波器上猜一百条专线都顶用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询