☰
高频方波注入原理与零速启动实现:无感FOC完整技术路线
2026/9/28 16:57:15 网站建设 项目流程

高频方波注入,这几个字在无感FOC圈子里讨论度一直不低,尤其是做空调压缩机、电动工具、水泵这类需要重载起动的项目,几乎绕不开。零速或者极低速下反电动势为零,传统滑模观测器、龙伯格观测器全部失效,这时候高频注入就是少数能干活的方案之一。这篇文章我把高频方波注入的原理、解调算法、参数选取和一份可以直接参考的代码示例一起放出来,给正在折腾电机零速启动的朋友一条完整的技术路线。

这篇文章适合两类人看:一是已经跑通FOC基础框架,但被零速低速段折磨的工程师;二是准备做无感FOC项目,正在做技术预研的硬件或算法工程师。前者可以直接跳到第4章拿代码,后者建议从第1章开始把原理过一遍。我会把我踩过的坑、试错过程中掉过的链子,以及最终稳定的调参经验全部写出来,尽量不让你再经历一遍。

需要说明的是,本文讨论的对象是PMSM永磁同步电机,凸极率的来源和表贴电机有区别,但方法论的迁移性很强。你手上如果是表贴电机,只要凸极率够用,同样可以套用。

1. 零速启动为什么难,先说清楚无感FOC的底层逻辑

1.1 反电动势法在中高速段很香,但在零速段失灵

无感FOC的核心难点在于,没有编码器,却要知道转子位置。中高速下,我们依赖的是反电动势——电机旋转时,转子上的永磁体在定子绕组中感生出电动势,这个电动势的相位包含着转子位置信息。

反电动势的大小和转速成正比,这是物理规律。转速为零时,反电动势也为零;转速很低时,反电动势只有一丁点。滑模观测器这类基于反电动势的算法,在10%额定转速以下信噪比就开始急剧恶化,到了5%以下基本就是乱跳,零速更是直接失效。

这不是观测器做得不好,而是物理层面信号就接近为零。你可以理解为在黑屋子里用眼睛找东西,还有微弱光线时勉强能看见轮廓,完全没光时眼睛再好也没用。反电动势法就是那对眼睛,而高频注入相当于自己带了一只手电筒。

1.2 抛开反电动势,还有什么信息能感知转子位置

既然反电动势靠不住,就得换一条路。电机定子绕组不是一个理想的电感,它的电感会随转子位置变化而变化——特别是IPM内嵌式永磁同步电机,d轴和q轴磁路有明显差异,凸极率通常在1.5到3之间。这种结构上的不对称,导致高频电流在不同转子位置下的响应不同。

思路就出来了:向定子绕组注入一个高频电压信号,然后去观察高频电流的响应。响应的差异里就藏着转子位置信息。由于高频信号是主动注入的,和反电动势无关,所以哪怕电机静止不动,信息也在那里。这就是高频注入能在零速工作最根本的原因。

高频注入根据波形分两类:高频正弦注入和高频方波注入。正弦注入起来绕、带宽低、需要滤波器;方波注入简单直接,数字化实现方便,而且不需要额外增加信号发生器,靠PWM中断时基就能做,非常适合单片机实现。

1.3 高低速方案如何配合:一个完整的无感FOC系统分工

实际工程中,单一观测器很难覆盖0到额定转速全域。我见过很多方案是这样一个分工:

  • 零速和低速段(0~5%额定转速):高频方波注入负责提供转子位置和速度
  • 中高速段(10%额定转速以上):滑模观测器或反电动势观测器负责
  • 中间区域(5%~10%):做切换过渡,可以用加权混合,也可以用状态机强制执行

为什么不能一个算法吃到底?因为高频注入在中高速时存在两个问题:一是基波电压变大,高频电流响应会被淹没,信噪比下降;二是注入频率和旋转频率混合,解调复杂度上升。反电动势法在高速段则越用越准,两个算法的优势区间恰好互补。

后面我会详细讲这个切换怎么做,重点是你需要在零速段把高频注入跑稳,切换只是水到渠成的事。

2. 高频方波注入的原理:凸极效应是怎么变成转子角度的

2.1 从磁路差异说起:为什么IPM电机天生适合高频注入

在数学模型上,IPM电机的d轴磁路会遇到更多的铁心饱和和磁阻变化,而q轴磁路相对通畅,这就形成了d轴电感小于q轴电感。这个差值越大,凸极率越高,高频注入的信号就越强,越容易解调。

对PMSM建立高频模型时,通常忽略电阻影响,只用电感特性来分析。在转子同步旋转坐标系下,高频电压与高频电流之间的关系可以通过一个包含转子位置信息的电感矩阵来描述。当观测器使用的估计坐标系与真实转子坐标系之间存在角度误差时,这个矩阵不再是对角阵,d轴的高频电压就会在q轴产生高频电流响应,q轴响应的大小正比于角度误差。

这一段原理比较抽象,我用一句话总结:只要转子位置估计不准,你注入的d轴电压就会在q轴电流上留下痕迹,而这个痕迹恰好可以用来自动修正角度误差。

2.2 方波注入 vs 正弦注入:为什么我选方波

我最早尝试的是高频正弦注入,用信号发生器原理注入5kHz正弦波,然后通过带通滤波器提取高频电流分量,再用乘法器解调。这套方案理论上很漂亮,但实际工程里滤波器带宽、相位延迟、数字化误差会把人搞到怀疑人生。

换成方波注入之后,清爽很多:

  • 方波电压由PWM占空比直接产生,不需要额外的DAC或者正弦表,只需在每个PWM周期交替改变注入电压符号
  • 解调时不需要带通滤波器,直接用相邻PWM周期的电流差值做差分运算,把低频分量和基波分量去掉,剩下高频响应
  • 信号带宽更高,动态响应快,对负载突变更从容

代价是注入电压是阶跃变化的,对电流采样点的噪声控制要求更高,同时方波注入会产生高频电磁噪声和转矩脉动,这个后面讲怎么压。

2.3 注入电压和注入频率怎么定

这是高频注入落地时最让人头疼的参数,我给一个经验范围,你按这个范围去试,比自己瞎猜快得多。

注入电压幅值:一般取电机额定电压的5%~15%。电压太低,高频电流响应太小,解调信噪比不足;电压太高,高频电流过大,转矩脉动和铁耗发热都会增加,还可能逼着电流调节器饱和。以310V直流母线、额定电压220V的压缩机电机为例,我常用12V到20V的注入幅值。

注入频率:方波注入的频率一般是开关频率的四分之一到二分之一。PWM开关频率10kHz时,常见注入频率是2.5kHz到5kHz。选太低,解调带宽不够;选太高,受到电流采样率和PWM分辨率限制。

还要考虑一个点:注入频率不能与电流环带宽、速度环带宽及其谐波重叠,否则会形成闭环耦合,引起振荡。我一般先把电流环设计好,再选注入频率,保证与电流环响应频率至少相差一个数量级。

3. 基于高频方波的转子位置观测器设计

3.1 位置误差信号的完整推导

虽然我不喜欢堆公式,但这个环节真的太关键,我把核心推导写出来,方便你理解代码里的每一行是怎么来的。

设真实转子坐标系为dq,估计坐标系为dq_est,两者夹角为theta_err。在估计坐标系下,考虑到d轴和q轴电感不同,高频电流增量方程可以近似为:

delta_i_d = v_h * dt * (L_avg - L_diff * cos(2*theta_err)) / (L_d * L_q) delta_i_q = v_h * dt * L_diff * sin(2*theta_err) / (L_d * L_q)

其中L_avg = (L_d + L_q)/2,L_diff = (L_d - L_q)/2。

看第二个公式:delta_i_q与sin(2*theta_err)成正比。当 theta_err 很小时,sin(2*theta_err) ≈ 2*theta_err,说明q轴高频电流增量直接反映了角度误差。这就是解调算法的数学基础。

但由于 v_h 是方波,正负交替,delta_i_q 也会跟着正负交替。解调时只要乘上当前的注入符号,就能把方波符号去掉,得到只和误差相关的量:

theta_err_signal = delta_i_q * sign(v_h)

这段代码实现起来就三行,但背后的数学要清楚,否则PLL出来全是乱的。

3.2 从误差信号到角度和速度:锁相环怎么搭

得到位置误差后,不能直接拿这个误差值当角度,因为它是带噪声的,而且误差信号是2倍角度的正弦,直接使用会抖动。标准做法是接一个锁相环,让PLL去跟踪真实角度,PLL输出就是平滑的估算角度和速度。

PLL内部是一个PI调节器加一个积分器。误差信号经过PI后得到估算速度,估算速度积分得到估算角度。当误差信号为零时,PLL锁定,估算角度等于真实角度。我用的PLL参数整定方法是:

  • 先确定解调环路等效增益,即误差信号的单位换算系数
  • 再根据期望的位置估计带宽(一般是速度环带宽的5到10倍),用带宽法计算PI参数

实际调试中,我习惯PLL响应稍微慢一点,优先保证稳定性和抗噪性,尤其是在带负载起动的场合。等起动稳定了,再根据动态需求调整带宽。带宽调太快,容易在重载下振荡;调太慢,动态响应跟不上,堵转时角度会滞后。

3.3 初始位置检测与磁极极性判断

高频方波注入有一个天然的麻烦:误差信号在theta_err=0和theta_err=pi时都可能是稳定平衡点,也就是说PLL可能收敛到正确位置,也可能收敛到反方向180度。开机什么都不知道的情况下,必须先把初始位置找出来。

我的做法分两步:

  1. 先发几个正反向电压脉冲,对比电流响应峰值,判断出磁极的N极还是S极,也就是判断d轴正方向
  2. 再用高频方波注入闭环,让PLL收敛到某一边,配合第一步的极性判断决定是否加180度偏置

第一步有现成的实现方法:在估计d轴正向注入一个窄电压脉冲,记录电流峰值;再在负向注入一个同样宽度的电压脉冲,记录电流峰值。由于磁路饱和效应,正方向电流峰值通常大于反方向,峰值大的方向就是磁极方向,即d轴正方向。

这块逻辑在零速启动里非常重要,很多零速起不来的案例都是初始位置错了180度,一通电就往反方向转。

提示:初始位置检测的脉冲电压宽度不能太宽,否则转轴会因为电磁转矩移动;也不能太窄,否则电流峰值不够分辨。具体宽度和幅值需要根据电机电感参数粗略估算后微调。

4. 代码实现:注入、解调、观测器一条龙

4.1 整体软件框架与中断时序

在开始代码之前,先明确软件架构。以我常用的gd32f527为例,PWM频率设在10kHz,一个PWM周期对应一次AD采样和一次电流环计算。高频方波注入频率选5kHz,也就是每两个PWM周期切换一次注入方向。

软件上拆成几个模块:

  • PWM下溢中断:电流采样、坐标变换、电流环PI、高频注入叠加、SVPWM更新
  • 高频注入模块:管理注入方向和时序
  • 解调模块:计算相邻周期电流差值,得到位置误差
  • PLL观测器模块:从误差信号得到角度速度
  • 状态机模块:负责零速检测、起动、低速/高速策略切换

中断执行顺序很重要。注入电压的切换必须和电流采样点错开至少一个PWM周期,否则当前的注入电压刚变化就采样,采样值会混入开关瞬态,导致解调出问题。我把注入符号切换放在PWM周期中间点,而电流采样放在PWM下溢点,中间隔了半个周期,实测稳定多了。

注意:注入符号切换和电流采样必须错开至少半个PWM周期。我见过不少样板直接把切换放在采样时刻,导致解调得到的误差信号里混入大量开关噪声,波形惨不忍睹。

4.2 高频方波注入与电流采样的对齐实现

先定义注入状态结构体:

typedef struct { float v_inj; // 注入电压幅值(V) int8_t sign; // 当前注入符号 +1 / -1 uint16_t half_period; // 半周期对应的PWM周期数(2) uint16_t pwm_count; // PWM周期计数 } hfi_inject_t;

在PWM下溢中断里,每次进入时计数器加一,判断是否到达切换点:

void hfi_inject_update(hfi_inject_t *inj, uint16_t pwm_period_count) { inj->pwm_count++; if (inj->pwm_count >= inj->half_period) { inj->pwm_count = 0; inj->sign = -inj->sign; // 翻转注入方向 } }

在电流环输出之后、坐标反变换之前,把注入电压叠加到d轴电压参考值上:

// 电流环输出 v_d_output = pi_d_update(...); v_q_output = pi_q_update(...); // 高频方波注入叠加,只加在估算的d轴 v_d_inject = v_d_output + inj.v_inj * inj.sign; // 反Park变换 + SVPWM ...

这样每次注入符号切换时,电压给到SVPWM,并在下一个PWM周期生效。采样点放在PWM下溢,也就是符号切换前的同一个周期内,本质上采样的是上一个注入方向下的响应。这样处理的好处是不需要额外的相位补偿,解调算法的各组电流差值都是同一种注入方向下的结果,误差可控。

4.3 位置误差解调与PLL代码

解调模块的核心逻辑是相邻两个PWM周期做电流差分,然后乘以当前注入符号。我在代码里保存上一拍的高频电流值,直接做差:

typedef struct { float i_d_prev; // 上一拍高频采样d轴电流 float i_q_prev; // 上一拍高频采样q轴电流 float theta_err; // 解调得到的位置误差 float gain_demod; // 解调增益系数 } hfi_demod_t; void hfi_demod_process(hfi_demod_t *demod, float i_d_fb, float i_q_fb, int8_t inj_sign) { float delta_i_q = i_q_fb - demod->i_q_prev; // 去掉方波符号影响,得到角度误差信号 demod->theta_err = delta_i_q * inj_sign * demod->gain_demod; // 保存当前值作为下一拍的“上一拍” demod->i_d_prev = i_d_fb; demod->i_q_prev = i_q_fb; }

注意这里的gain_demod不是随便设的,它需要把电流增量转换为弧度。实际计算时,可以先用标定法得到角度误差和输出信号的比例。我通常是让PLL的输入单位本来就是任意比例,然后在PLL里通过pi参数统一吸收,但为了方便调试,还是把gain_demod设为1,后面用PLL带宽去解释。

PLL观测器代码:

typedef struct { float theta_est; // 估算角度(rad) float speed_est; // 估算速度(rad/s) float i_error_integral; // 速度环积分项 float kp_pll; float ki_pll; float dt; // 控制周期(s) } hfi_pll_t; void hfi_pll_update(hfi_pll_t *pll, float theta_err) { // PI调节器:误差 -> 角速度 pll->speed_est = pll->kp_pll * theta_err + pll->i_error_integral; // 角速度积分 -> 估算角度 pll->theta_est += pll->speed_est * pll->dt; } void hfi_pll_integral_update(hfi_pll_t *pll, float theta_err) { pll->i_error_integral += pll->ki_pll * theta_err * pll->dt; }

在中断中调用顺序:

// 1. 采样电流、坐标变换得到 id_fb / iq_fb // 2. 高频解调 hfi_demod_process(&hfi_demod, id_fb, iq_fb, inj.sign); // 3. PLL积分项更新 hfi_pll_integral_update(&hfi_pll, hfi_demod.theta_err); // 4. PLL主更新 hfi_pll_update(&hfi_pll, hfi_demod.theta_err); // 5. 电流环使用估算角度做Park变换和反Park ...

把PLL积分项更新放在主更新之前,等于用当前拍误差先修正速度再更新角度,能减少一拍延迟,实际对起动过程稳定有明显帮助。

4.4 零速起步到中速段的策略切换

高频注入跑到一定转速后,要让位于反电动势法。我用的切换策略是“速度阈值 + 角度互锁”。

状态机先定义两个算法都有估算角度和估算速度,命名如下:

  • theta_hfi, speed_hfi:高频注入观测器输出
  • theta_smo, speed_smo:滑模或反电动势观测器输出
  • theta_use, speed_use:最终用于坐标变换和速度环的输出

在高速段,speed_smo大于切换阈值后,先用一个互锁逻辑确保两边角度差小于某个阈值(比如30度),然后把最终角度改为smo侧。为了防止突变,我做了一个加权过渡:

// 过渡系数alpha,0表示完全用HFI,1表示完全用SMO float alpha = 0.0f; if (speed_ref > switch_high) { alpha += alpha_step; // 按固定步长往上加 if (alpha > 1.0f) alpha = 1.0f; } else if (speed_ref < switch_low) { alpha -= alpha_step; if (alpha < 0.0f) alpha = 0.0f; } // 角度需要做边界处理,避免-π/π跳变 float delta = theta_smo - theta_hfi; if (delta > PI) delta -= TWO_PI; if (delta < -PI) delta += TWO_PI; theta_use = theta_hfi + alpha * delta; speed_use = (1.0f - alpha) * speed_hfi + alpha * speed_smo;

这个过渡的思路是:在切换区间内同时用两个观测器的信息,让角度从HFI平滑过渡到SMO。切换点一般选在额定转速的10%附近,切换阈值不能设太窄,否则负载波动会让观测器来回切换,电流和速度都会振荡。

5. 调试实录:常见问题与排查方法

5.1 起动瞬间电流冲击大,甚至过流保护

这个现象我第一次调高频注入时也遇到过,主要原因通常是初始位置检测不准,或者注入幅值过大。

排查步骤:

  1. 先把初始位置检测单独跑一遍,打印出检测角度和实际电机静止位置,看是否偏差特别大
  2. 用示波器看电流波形,如果起动瞬间高频电流峰值超过额定电流好几倍,就先降低注入电压幅值
  3. 如果电流冲击是方向性的,很可能是180度反了,检查磁极极性判断逻辑

我遇到过的一个坑是:初始位置检测时用带通滤波器处理信号,滤波器相位延迟没补偿,导致检测角度偏差20多度,一通电电流直接冲顶。去掉滤波器、改用直接差分后问题消失。

5.2 位置估算抖动大,起动后电机来回震动

位置抖动大,最常见的原因是解调信号噪声大、PLL带宽过高,或者PLL参数不合适。高频注入本身的信号就是脉冲化的,如果PLL带宽比注入频率还高,那些高频分量全都会进入速度输出,震动是必然的。

我建议把PLL带宽控制在20Hz到80Hz之间,具体取决于系统惯量和负载。压缩机这种大惯量负载带宽取低一些,动态要求高的伺服负载取高一些。另外检查一下注入频率和电流环带宽有没有重叠,重叠了就把注入频率或电流环带宽错开。

还有一个容易忽视的点:死区时间。死区会造成电压误差,影响高频电流的解调。如果注入电压幅值比较小,死区的影响占比就高,抖动会明显。可以加逆变器死区补偿,或者适当提高注入幅值。

5.3 高频注入噪声如何压

高频方波注入的代价之一就是电磁噪声,电流里会有明显的高频分量,电机也会发出尖叫声。噪声来源有几个方面:

  • 注入频率刚好落在人耳敏感区间,选注入频率时尽量避开2kHz到4kHz,或者你本身不介意噪声,否则留意一下
  • 注入电压偏大,不需要那么大的信号响应,适当减小
  • 解调后的谐波分量,可以加一个低通滤波器把PLL输入信号稍微滤一下,但不能滤太狠,滤多了会引入相位延迟

我刚做第一版时用的是3.5kHz注入,泵体噪声明显,调到5kHz后好了一些,同时在电流采样上加了一个一阶低通滤波,相位在注入频率下延迟不到20度,效果可以接受。

5.4 参数整定速查表

把我在实际项目中用过的参数范围和调整逻辑整理成表,方便你直接抄:

参数参考范围影响调试建议
注入电压幅值额定电压的5%~15%信号强度、噪声、发热从下限开始往上加,直到起动稳定
注入频率开关频率的1/4~1/2解调带宽、听觉噪声避开人耳敏感区间,与电流环带宽错开
解调方式相邻周期差分延时、噪声无滤波器优先,必要时加一阶低通
PLL带宽10Hz~80Hz动态响应、抗噪性从低往高调,以系统不过冲为准
切换阈值额定转速的5%~15%切换平稳性先小范围测,再逐步扩大

这份表是我花了大量时间反复试出来的,每个参数都有牵一发动全身的效果,建议一次只改一个参数,改完看波形,再做下一步调整。

最后说点操作层面的体会。高频方波注入这套东西,原理书上都写得清楚,真正难的是把零速定位稳、把初始位置判对、把切换调顺。我一开始自信满满,以为代码对着论文抄一遍就能跑,结果在零速起动这里折腾了快两周,最后发现问题全出在细节上:采样点对没对齐、初始N/S判反了、PLL参数太激进。后来我把整个流程拆成注入、解调、PLL、切换四个独立模块,每个模块单独打印数据和波形,问题才一个个浮出来。调试无感FOC,最快的路径永远是先把模块拆干净,每个模块都可视、可测、可独立调,然后再合起来跑系统。希望这篇文章能帮你少走我走过的弯路,也欢迎在实际项目里踩到新坑后回来一起交流。

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

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

立即咨询