ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

单电阻PMSM无传感FOC全解析:SMO+PLL+电压重建方案

单电阻PMSM无传感FOC全解析:SMO+PLL+电压重建方案

做电机驱动这段时间,被问得最多的一个组合需求就是:省掉编码器,同时把采样电阻从三个减成一个。这两个需求合在一起,就是标题里的这套单电阻PMSM无传感控制方案。我基于TMS320F28035把模型和代码完整跑通过一轮,算法路线正好是标题里那四块:SMO滑模观测器负责估反电动势,单电阻采样负责从母线电流里恢复三相电流,PLL负责把反电动势变成平滑的转角和转速,电压重建负责把指令电压修正成观测器能信得过的实际电压。

这套方案看起来参数不多,真正落地要处理的是采样时序、参数标幺、启动切换和一堆边界条件。适合正在做FOC样机、想把编码器省掉的工程师,也适合想彻底搞明白单电阻采样和滑模观测器原理的同学。我会把整条信号链拆开讲,附上可以往工程里搬的核心代码,以及调试中反复遇到的几个典型问题。

1. 一套省去编码器和三电阻采样的FOC方案,为什么大家都这么搭

1.1 成本账与工程账,先把方案的动机算清楚

先说省成本这件事。一个增量式编码器加上安装结构,成本常常占整个驱动板的五分之一甚至更多,而且在振动大、油污多、温度高的场合,编码器反而是最脆弱的部件。去掉它以后,电机侧只剩三根相线,系统的可靠性和体积都会改善。代价是位置信号必须从电流和电压里“估”出来,这对观测器提出了很高的要求。

电流采样侧的减法也一样。三电阻方案需要三个采样电阻、三路差分放大、三路ADC,布局时每一路都要考虑共地和噪声隔离。单电阻方案只需要母线负端一个精密采样电阻,一路放大,一个ADC通道,从硬件上说清爽太多。但它把难度转移到了软件上:一个采样点不可能同时给出三相电流,必须利用PWM开关状态的窗口去“重构”。

所以把这两个需求叠在一起,就得到了一个典型的低成本无传感FOC硬件形态:单电阻采样 + 无位置传感器。而算法栈之所以是SMO、PLL、电压重建这套组合,是因为它们各自解决了一个不可回避的问题:SMO从电流和电压里估出反电动势,PLL从反电动势里提取出平滑的转子角度和转速,电压重建则保证喂给SMO的电压足够接近真实施加在电机上的电压。三者缺一个,整条链都不成立。

方案成本采样质量算法负担典型应用
编码器 + 三电阻高最好最低伺服、低速高精度
无传感 + 三电阻中好中通用变频器
无传感 + 单电阻低中下,需重构高风机水泵、小功率家电

单电阻方案的电流质量在低调制区会明显变差,这决定了它对控制算法的鲁棒性要求更高,后面我会专门说这个坑。

1.2 信号链一图看懂:谁在给谁喂数据

整个系统的信号流可以这样看。FOC主回路还是老一套:单电阻重构出三相电流,经过Clarke变换得到电流,再经过Park变换得到d/q轴电流,电流环PI输出交直轴电压,逆Park得到两相静止坐标系下的电压指令,最后经过SVPWM输出六路PWM驱动逆变器。

观测器部分则挂在主回路旁边,单独拉一条数据链。SMO需要的输入是两样东西:一个是αβ轴下的电流,可以从重构后的三相电流直接变换得到;另一个是αβ轴下的实际电压,这个不能直接拿逆Park输出的电压指令,而要由电压重建模块去算。SMO输出估算反电动势,PLL再吃下这组反电动势,输出转子电角度和电角速度,角速度送给速度环,角度则送回Park变换和逆Park变换。

这里最容易被忽略的就是电压重建。很多人一开始直接用指令电压喂给SMO,想着反正SVPWM不是已经输出了吗?但指令电压只是“希望”施加的电压,实际经过死区、管压降、母线电压波动之后,真正落在电机上的电压已经变了。观测器喂进去的电压不准,估出来的反电动势自然不准,位置就跟着漂。所以电压重建不是锦上添花,而是这套无传感方案里绕不开的一环。

2. 28035上的单电阻采样:在PWM事件里“偷”三相电流

2.1 单电阻采样的物理约束:三相加起来为零,但采样窗口只有一个

电机三相电流满足基尔霍夫定律,三相瞬时电流之和为零,所以理论上只要知道两相,第三相就能算出来。问题是单电阻只放在母线负端,它上面流过的电流并不是某一相连续的电流,而是随着PWM开关状态变化的母线电流。

中心对齐PWM下,每个开关周期的正中间,逆变器通常会有一个有效的电压矢量正在作用,此时母线电流就等于某一相电流。具体是哪一相,取决于当前电压矢量所在的扇区和开关组合。工程上有一套固定的对应关系:

有效电压矢量开关组合(a b c)母线电流等于
V1100Ia
V2110-Ic
V3010Ib
V4011-Ia
V5001Ic
V6101-Ib

可以看到,每一个有效矢量对应的母线电流,要么是某相电流,要么是某相电流的负值。所以只要在PWM周期里找到两个合适的、分属不同有效矢量的采样点,就能拿到两相电流,第三相用KCL补齐。

问题在于,这两次采样不是随时都成功的。当电压矢量接近扇区边界,或者调制比很低的时候,某个有效矢量的作用时间可能只有几百纳秒,而ADC从采样保持到转换结束至少需要一段时间,窗口不够就采不准。这是单电阻方案最核心的物理约束,也是后面很多调试问题的根源。

2.2 ePWM与ADC的同步方案:采样时刻决定电流质量

TMS320F28035上的ADC触发源可以直接挂到ePWM模块的事件上,不需要CPU介入,这给单电阻采样提供了很大的便利。我把ADC的SOC触发源配置成ePWM计数器的比较事件,让ADC在一个载波周期的前半个有效矢量窗口和后半个有效矢量窗口分别触发一次采样。两个采样点都在有效矢量的中间段,尽量避开开关切换引起的振铃。

配置思路大概是这样:

// ePWM1负责第一路电流采样触发 EPwm1Regs.TBCTR = 0x0000; EPwm1Regs.TBPRD = PWM_PERIOD; // 换算成10kHz EPwm1Regs.CMPA.bit.CMPA = SAMPLE_POINT_1; // 前半个周期采样点 EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_CMPA; // 比较匹配触发 EPwm1Regs.ETSEL.bit.SOCAEN = 1; EPwm1Regs.ETPS.bit.SOCAPRD = ET_1ST; // ePWM2负责第二路电流采样触发,比较点设在周期后半段 EPwm2Regs.TBPRD = PWM_PERIOD; EPwm2Regs.CMPA.bit.CMPA = SAMPLE_POINT_2; EPwm2Regs.ETSEL.bit.SOCASEL = ET_CTR_CMPA; EPwm2Regs.ETSEL.bit.SOCAEN = 1; EPwm2Regs.ETPS.bit.SOCAPRD = ET_1ST;

两个采样点之间至少要隔开一个ADC转换周期,并且各自对应的有效矢量窗口都要足够宽。如果某一拍的某个窗口太窄,就不能再用它采相电流,这时候要么对SVPWM做最小脉宽限制,要么退回到上一拍的重构结果做保持。我后面会在调试章节详细讲这个处理。

2.3 电流重构的最小实现

重构逻辑本身不复杂,核心是根据当前PWM周期使用的矢量,把两次母线采样值翻译成ia和ib,再用ia + ib + ic = 0算出ic。

typedef struct { float ia; float ib; float ic; } PhaseCurrents; PhaseCurrents Reconstruct_Cuurent(int sector, float sample1, float sample2) { PhaseCurrents cur; switch (sector) { case 1: cur.ia = sample1; cur.ib = -sample2; break; case 2: cur.ia = sample1; cur.ic = -sample2; break; case 3: cur.ib = sample1; cur.ic = -sample2; break; case 4: cur.ia = -sample1; cur.ic = sample2; break; case 5: cur.ib = -sample1; cur.ic = sample2; break; case 6: cur.ia = -sample1; cur.ib = sample2; break; default: break; } cur.ic = -cur.ia - cur.ib; return cur; }

上面的扇区编号对应经典SVPWM的六个扇区划分,每次进中断先根据当前角度和电压矢量方向确定扇区,再取两次ADC结果做映射。实际工程里,sector和采样点的对应关系必须根据自己PWM模块的配置仔细对表,这也是最容易写反的地方。

3. SMO滑模观测器的落地方案:符号函数、滤波与增益的取舍

3.1 观测器模型:αβ轴下的两个电流方程

滑模观测器建立在αβ轴系的PMSM电压方程上。表贴式PMSM的电压方程可以写成:

  • L·dia/dt = Va - R·ia - Eα
  • L·dib/dt = Vb - R·ib - Eβ

其中Eα和Eβ就是转子旋转产生的反动势,它们的相位直接反映了转子位置。SMO的思路是构造一个电流估计模型,把实测电流与估计电流的误差通过开关函数拉回滑模面,当估算电流和实测电流一致时,开关函数输出的等效值就约等于反电动势。

观测器方程写成:

  • L·d(ia_hat)/dt = Va - R·ia_hat - k·sgn(ia_hat - ia)
  • L·d(ib_hat)/dt = Vb - R·ib_hat - k·sgn(ib_hat - ib)

当滑动模态建立起来之后,估算电流逼近实测电流,开关函数中的高频分量经过等效控制平均,剩下的低频量就是反电动势Eα和Eβ。这个方法的鲁棒性来自开关控制本身:只要增益足够大,它对电阻、电感参数的偏差以及电压误差都有很强的“拉回”能力,这也是它在工程里比卢恩伯格观测器更好用的原因。

3.2 代码实现:从电流误差到等效反电动势

实际代码里,我会用一个结构体保存观测器状态,用一阶低通滤波器处理开关函数输出,得到平滑的反电动势。

typedef struct { float Rs; // 定子电阻,Ω float Ls; // 定子电感,H float Ts; // 控制周期,s float kSMO; // 滑模增益 float alpha; // 低通滤波系数 float ia_hat; float ib_hat; float ea_f; float eb_f; } SMO_Obj; void SMO_Run(SMO_Obj *o, float ia, float ib, float va, float vb, float *ea, float *eb) { float err_ia = o->ia_hat - ia; // 估算电流减实测电流 float err_ib = o->ib_hat - ib; float za = (err_ia > 0.0f) ? o->kSMO : -o->kSMO; float zb = (err_ib > 0.0f) ? o->kSMO : -o->kSMO; // 电流估计方程,显式欧拉离散 o->ia_hat += o->Ts * (va - o->Rs * o->ia_hat - za) / o->Ls; o->ib_hat += o->Ts * (vb - o->Rs * o->ib_hat - zb) / o->Ls; // za/zb的等效值就是反电动势,低通滤掉高频抖振 o->ea_f += o->alpha * (za - o->ea_f); o->eb_f += o->alpha * (zb - o->eb_f); *ea = o->ea_f; *eb = o->eb_f; }

这里有个容易犯错的点:符号函数里的误差方向是“估算电流减实测电流”,反电动势估计值取za本身。如果反了,观测器会发散而不是收敛。我第一次移植时就是因为符号写反,电流估计直接飞了,后来对着模型推了一遍才发现。

3.3 增益与滤波系数怎么定

滑模增益kSMO的选择很考验经验。kSMO太小,滑模面建立不起来,估算电流跟不上实测电流,反电动势估计会是一个衰减振荡;kSMO太大,抖振明显,高频分量灌进PLL之后位置噪声变大。我的做法是从0.1×Vbase开始试,观察电流估计误差能否在几个毫秒内被“吸”到零,能吸进去但噪声偏大就往下调,吸不进去就往上加。

低通滤波系数alpha决定了反电动势信号的光滑程度。alpha太小,反电动势被滤得过于平滑,相位滞后严重,位置估计会在动态工况下明显滞后;alpha太大,滤波基本不起作用,抖振直接传到角度。一般取alpha对应的截止频率在50Hz到200Hz之间,具体要看电机基频范围。基频越高,截止频率也要跟着提高,否则高速时反电动势相位补偿不过来。

低通滤波带来的相位滞后是一个绕不开的问题,最简单的补偿办法是查表给估算角度加一个随转速变化的补偿角。更省事的做法是让PLL自己消化这个滞后,实际跑下来效果也够用,缺点是带宽不能调太高。

4. PLL锁相环从反电动势里提取角度:参数只有两个,坑却有七八个

4.1 为什么不直接用atan2:抖动、跳变、速度毛刺

SMO输出的反电动势本质上是一对随转子位置变化的正弦信号,理论上用atan2(Eβ / Eα)就能得到转子角度。但工程上几乎没人直接这么做。原因很简单:反电动势信号含有抖振和谐波,直接atan2出来的角度会毛刺满天飞,而且角度会发生从π到-π的跳变,这个跳变一旦进入Park变换,电流环输出会瞬间跳一大格。

PLL本质上是一个二阶闭环跟踪器,它把角度和速度当成一个整体去跟踪,而不是逐点求反正切。它有惯性,有阻尼,对反电动势中的谐波和毛刺有天然的平滑作用,同时还能直接输出一个经内部速度积分得到的光滑转速信号。所以SMO后面挂PLL,不是多此一举,而是让整个估算器从“观测”变成“伺服”。

4.2 PLL的误差信号与环路结构

PLL的核心是根据反电动势建立误差信号。令Eα和Eβ为反电动势观测值,构造误差:

err = (-Eα·cos(θest) - Eβ·sin(θest)) / |E|

当θest接近真实转子角度时,这个误差近似等于sin(真实角度与估计角度的差),归一化之后幅值不再随转速变化,PLL带宽就能在全速范围内保持相对一致。然后误差经过PI调节器去修正速度积分器的输出,再累加出角度。

参数整定上,我习惯把PLL看成一个典型的二阶系统,自然频率ωn和阻尼比ζ是关键。比例增益kp近似等于2·ζ·ωn,积分增益ki近似等于ωn²。ωn的选择要结合速度环带宽:带宽太小,动态跟随慢,速度突变时角度会“拖后腿”;带宽太大,系统又容易引入噪声,甚至和机械谐振耦合。我一般取速度环带宽的3到5倍,同时保证远低于采样频率的十分之一。

4.3 PLL代码骨架与正方向陷阱

下面是我在28035上用的PLL核心代码,代码里kpi和ki按照上面的思路计算,具体值需要在台架上微调。

typedef struct { float kp; // 比例增益 float ki; // 积分增益 float theta; // 电角度估计,rad float omega; // 电角速度估计,rad/s float Ts; // 周期,s } PLL_Obj; void PLL_Run(PLL_Obj *o, float ea, float eb) { float emag = sqrtf(ea * ea + eb * eb); float err; if (emag < 0.01f) return; // 反电动势太小,守住当前状态 err = (-ea * cosf(o->theta) - eb * sinf(o->theta)) / emag; o->omega += o->ki * err * o->Ts; o->theta += (o->omega + o->kp * err) * o->Ts; // 角度越界处理 o->theta = fmodf(o->theta, 2.0f * 3.14159265f); }

这个代码里符号方向是按常用的反电动势符号约定推的,但如果你在自己的工程里发现PLL锁到了错误角度,不要怀疑硬件,先把err那行的符号取反试试。我碰到过两次,都是因为SMO输出的反电动势方向定义和PLL的约定不一致,导致角度估计和真实位置永远差一个固定角度。检查方法很简单:开环运行,把估算角度和实际角度同时打出来,看到它们同步变化但恒定相差某个值,那就是正方向问题。

5. 电压重建没有想象中简单:死区、零序和采样时刻

5.1 指令电压和实际电压之间存在什么

很多人以为SVPWM算出来的占空比直接就是施加在电机上的电压,实际差得远。第一,死区时间里开关管不导通,相电压被拉低;第二,开关管的导通压降和续流二极管压降会造成额外的电压损失;第三,母线电压不是恒定值,整流滤波后的母线会随负载波动;第四,SVPWM本身为了充分利用母线电压会注入零序分量,使三相占空比之和偏离恒定值。

SMO的反电动势估计建立在电压方程上,如果输入电压比真实电压偏大或偏小,反电动势估计就会产生偏差,最终表现为位置误差。这类误差在低速时尤其致命,因为低速时反电动势本身就小,一点电压偏差就能让信噪比恶化。

5.2 基于母线电压和实际占空比的三相电压重建

所以电压重建不能拿指令值直接算,而要拿真正写入PWM寄存器的那个占空比,再叠加上实测母线电压。具体实现上,我用过下面这个公式,它天然考虑了三相占空比的零序分量:

  • Va = Vbus × (2·da - db - dc) / 3
  • Vb = Vbus × (-da + 2·db - dc) / 3
  • Vc = Vbus × (-da - db + 2·dc) / 3

原理是先从三相桥臂电压的平均值得到中性点电位,再让各相相电压减去中性点电位。这样得到的相电压是星形负载下的真实相电压,SVPWM注入的零序分量被自然消掉了。

void Voltage_Reconstruct(float vbus, float da, float db, float dc, float *va, float *vb, float *vc) { float vn = vbus * (da + db + dc) / 3.0f; *va = vbus * da - vn; *vb = vbus * db - vn; *vc = vbus * dc - vn; }

这三个电压再经过Clarke变换,就是SMO需要的Va和Vb。要注意的是,da、db、dc必须是当前周期实际装载的PWM比较值对应的占空比,而不是电流环输出后、SVPWM运算前的参考值。很多第一次实现的人会拿错变量,导致重建电压和实际输出电压之间出现一个周期的延迟,这个延迟会让位置估计相位超前或滞后。

5.3 死区补偿的最小方案

电压重建能修正占空比和母线电压的直接影响,但死区和管压降是另一个维度的误差源。最简单的死区补偿方法,是根据电流极性给相电压加一个固定的补偿量。

typedef struct { float vbus; float vdead; // 死区与管压降折算后的等效补偿电压 } VoltRecon; void Volt_Recon_Comp(VoltRecon *o, float da, float db, float dc, float ia, float ib, float ic, float *va, float *vb, float *vc) { float vn = o->vbus * (da + db + dc) / 3.0f; *va = o->vbus * da - vn; *vb = o->vbus * db - vn; *vc = o->vbus * dc - vn; if (ia > 0.02f) *va += o->vdead; else if (ia < -0.02f) *va -= o->vdead; if (ib > 0.02f) *vb += o->vdead; else if (ib < -0.02f) *vb -= o->vdead; if (ic > 0.02f) *vc += o->vdead; else if (ic < -0.02f) *vc -= o->vdead; }

vdead不要只按理论公式算,更可靠的办法是在台架上实测。先锁住直流母线,给定一个固定占空比,用电压探头测实际相电压,反推vdead。这个值在电流过零附近会变得很不稳定,所以代码里设了0.02A的小阈值,避免电流过零时误动作。

6. 把估算器接进FOC主循环:标幺化、启动序列与中断结构

6.1 标幺化:换电机不换观测器参数的关键

无传感系统最怕的就是换一台电机,观测器参数全得重调。解决这个问题的关键是把电学量全部标幺化。我用的基值定义是:电压基值为相电压峰值对应的值,电流基值为额定电流峰值,转速基值为额定电角速度。电阻基值由Vbase/Ibase给出,电感基值由Rbase/ωbase给出。

标幺化之后,SMO里那个增益kSMO的取值范围就变得统一了,不再跟着电机功率等级变化。换一台功率大一倍、电压等级相同的电机,电机的标幺电阻电感和上一台接近,观测器参数基本可以平移过去。这是我在多台样机之间移植代码最省事的一个习惯。

参数基值定义单位
电压基值 Vbase相电压峰值V
电流基值 Ibase额定电流峰值A
转速基值 ωbase额定电角速度rad/s
电阻基值 RbaseVbase / IbaseΩ
电感基值 LbaseRbase / ωbaseH

6.2 从开环I/f到无传感闭环的切换序列

无传感系统不能启动就切入SMO闭环,因为零速时反电动势为零,观测器什么都估不出来。工程上的标准做法是用I/f开环强拉启动:速度环不工作,d/q轴电流由程序直接给定,q轴电流维持一个固定幅值,角度由程序线性递增,按斜坡把转速慢慢拉起来。

启动切换的整体序列可以简化成下面的状态机:

if (state == START_IF) { freq_ref += freq_ramp * Ts; // 频率斜坡 theta_ref = fmodf(theta_ref + freq_ref * Ts, 2pi); id_ref = 0.0f; iq_ref = I_START_AMP; // 反电动势达到阈值,PLL角度预置,准备切换 if ((freq_ref > FREQ_SWITCH_THRESH) && (est_emag > E_TH)) { pll.theta = theta_ref; pll.omega = freq_ref; state = CLOSED_LOOP; } } else if (state == CLOSED_LOOP) { theta_ref = pll.theta; // 切换到观测器角度 speed_fb = pll.omega; iq_ref = speed_pi_output; // 速度环接管 }

这里有两个细节特别重要。一是PLL的初始角度一定要预置成当前I/f开环的角度,否则切换瞬间角度跳变,电流会猛地打一个趔趄。二是iq_ref不要直接从固定启动幅值直接切成速度环输出,建议加一个200ms左右的渐变斜坡,让电流环平稳过渡。

6.3 10kHz中断里的主循环框架

整个控制在ADC中断里完成,28035处理10kHz的控制频率压力不大。中断服务的顺序决定了数据流动的时间一致性,我的安排是:先做电流重构,再做坐标变换和电流环,然后算SVPWM,最后跑观测器。

interrupt void FOC_ISR(void) { // 1. 从两次ADC结果重构三相电流 PhaseCurrents cur = Reconstruct_Sample_And_Update(); // 2. Clarke + Park float i_alpha = cur.ia; float i_beta = (cur.ia + 2.0f * cur.ib) * INV_SQRT3; float i_d = i_alpha * cosf(theta) + i_beta * sinf(theta); float i_q = -i_alpha * sinf(theta) + i_beta * cosf(theta); // 3. d/q轴电流环PI,得到vd、vq // 4. 逆Park得到v_alpha_ref、v_beta_ref,送SVPWM // 5. 电压重建:用实际占空比和母线电压算观测器电压 // 6. SMO估算反电动势 // 7. PLL更新角度和速度 // 8. 写PWM比较寄存器 }

这个顺序里电压重建要放在SVPWM计算之后,因为观测器需要的是“真正写到PWM寄存器”的占空比,如果用电流环输出值来算,就会引入一拍的误差。观测器放最后,让SMO吃到的电流采样值、电压重建值和当前PWM输出都是同一拍的数据,时间对齐很重要。

7. 调试实录:哪些坑是我反复踩过的

7.1 重构电流在低速时出现锯齿失真

第一次跑通无传感闭环时,速度一降到5%额定转速以下,电流反馈就开始出现周期性锯齿,电流环明显高频振荡。当时第一反应是采样电阻的噪声问题,加电容、加滤波全试过,效果都不明显。后来用示波器同时抓VSENSE波形和PWM输出,才发现问题根本不是噪声,而是采样点落到了窄脉冲窗口里。

低速情况下,合成电压矢量的模长很小,SVPWM出的有效矢量脉冲宽度不够,ADC还没来得及完成采样保持,窗口就结束了。这时候采到的母线电流是多个开关状态的混合,重构出来的相电流自然就是锯齿状。

解决办法分两步。第一步是在SVPWM输出端加最小脉宽限制,任何有效矢量的持续时间不得小于1.5μs左右,不足的部分按比例调整相邻矢量,尽量保持合成矢量的幅值和方向不变。第二步是给ADC采样点做自适应偏移,当某个窗口过窄时,把采样点往窗口更宽的一侧挪。如果两个窗口都不可用,就用上一拍的重构结果暂时代替,但要加滞环和限幅,不能长时间用历史数据,否则电流环会“飞”。

7.2 位置估计总带6倍电频率脉动

换到中高速稳定运行之后,用临时编码器做对照,发现位置估计误差里始终含有一个明显的6倍电频率成分,转矩电流也跟着周期性波动。这个现象很有规律,只要是三相系统,出现6倍频分量基本都指向三相不对称或死区效应。

排查过程是把电压重建模块的估算电压和示波器实测线电压做对比。一开始没加死区补偿,相电压在电流过零附近有明显的凹陷;加上5.3节的死区补偿后,6倍频脉动幅值降下去一大截。剩下的一小部分来自电流重构误差在扇区切换时的突变,通过进一步优化最小脉宽限制和采样点位置后,基本被压到可接受范围。

这个坑提醒我一个原则:不要急着在PLL上加重滤波去压脉动,滤波只是掩盖问题。先确认电压重建和电流重构这两个“输入端”是干净的,再考虑怎么处理反电动势里的残余谐波。

7.3 启动切入闭环瞬间过流

切换瞬间过流是我最后才解决的坑。现象是开环I/f强拉阶段一切正常,一到切换条件满足、状态机跳到闭环,q轴电流瞬间顶到限流值,运气不好还会触发硬件过流保护。

当时我先怀疑电流环PI输出突变,但检查后发现问题出在角度跳变。状态机切闭环时,PLL才刚开始从零角度积分,而I/f阶段的角度已经走了很远,两个角度相差几十度。Park变换突然用这个错误的反馈角度去算id/iq,电流环为了追上错误的反馈值,输出电压直接冲到饱和。

修复办法就是6.2节说的那两步:切换前把PLL的theta预置成当前theta_ref,omega预置成freq_ref;切换后iq_ref从启动电流值开始,用斜坡在200ms内渐变到速度环输出。这样切换瞬间电流变化率就小很多。再把切换阈值提高一点,确保反电动势幅值足够大、PLL有足够的信噪比去锁定。

最后再说一个我自己的调试习惯。很多人一上来就把无传感闭环从头到尾跑通才开始看波形,这样很难定位问题。我的做法是:先开环I/f运行,把SMO和PLL当作“观测仪表”跑起来,在示波器上同时观测估算角度和真实电流相角,确认估算角度与真实位置趋势一致,再让PLL输出切入电流环。每一步都在上一个节点验证过了,最后无传感启动基本就是一次过。这套方案真正花时间的不是算法本身,而是把采样和电压这两个输入伺候干净。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进