作为一名常年在电机驱动现场打滚的工程师,我可以说:永磁同步电机参数辨识,是所有FOC控制项目里最绕不过去、又最容易被低估的一个环节。很多团队把电流环速度环都调通了,一换电机型号就抓瞎,根源往往不是算法框架不好,而是参数表没填对。从原理到代码实现,我想把这一整套流程按我的实际操作方式完整讲一遍。
这篇文章不是给你抄一个“万能公式”,而是告诉你:电机参数到底有哪些、离线在线怎么测、为什么最小二乘能干活、代码该怎么落到MCU里,以及现场哪些坑我不能让你再踩一遍。无论你是刚接触FOC的在校生,还是已经被弱磁、MTPA折磨过的驱动工程师,这篇都能让你少走几个月弯路。
1. 永磁同步电机参数辨识到底在辨识什么
1.1 先给电机做个体检:参数清单与扮演的角色
拿一台新的永磁同步电机,铭牌上通常只有额定电压、额定电流、额定转速和额定功率。但FOC控制器需要的信息远比这多。我们把参数分成两类:电气参数和机械参数。
| 参数 | 符号 | 在控制中的作用 |
|---|---|---|
| 定子电阻 | Rs | 电流环PI的零点配置、铜耗估算、低速稳态精度 |
| d轴电感 | Ld | 电流环带宽、弱磁控制、MTPA轨迹 |
| q轴电感 | Lq | 电流环带宽、转矩响应、交叉耦合补偿 |
| 永磁磁链 | ψf | 反电动势大小、转矩常数、弱磁转折速度 |
| 转动惯量 | J | 速度环带宽、加减速响应、抗扰动性能 |
| 阻尼系数 | Bv | 摩擦与风阻,通常在惯量辨识中一并估计 |
这些参数没有一个是可以拍脑袋定的。电流环PI参数直接依赖电阻和电感,速度环PI直接依赖转动惯量。如果参数偏差超过20%,你调出来的环可能在一个转速段稳定,在另一个转速段就振荡。
最典型的是磁链。永磁体磁链受温度影响非常大,温度每升高100℃,磁链可能下降约10%到15%。如果你用常温下测到的磁链去做弱磁,高速区间电流轨迹就全偏了。
1.2 这件事为什么不好做:耦合、可变性与可观测性
很多人一开始不理解,参数辨识为什么不能像测电阻一样拿万用表点两下就完事。原因很简单:电机在运行的时候,d轴和q轴电压方程是耦合的。
dq坐标系下的稳态电压方程是这样的:
ud = Rs·id - ωe·Lq·iq uq = Rs·iq + ωe·Ld·id + ωe·ψf
你可以看到,d轴电压不仅和Rs、Ld有关,还和Lq、iq有关。q轴电压更是同时包含Rs、Ld、ψf。这意味着你单独测d轴电压,没法唯一解出Rs和Ld;单独测q轴电压,也没法把Ld和ψf分开。
这就是可观测性问题。我用一个开车的类比:你一直匀速直线行驶,只能知道油门和车速的关系,没法同时分辨轮胎滚动阻力和空气阻力;只有你不断变道、加速、刹车,提供足够丰富的激励,各个参数的作用才能被区分出来。参数辨识的核心,就是设计合适的激励,让每个参数都“被看见”。
另外,参数本身不是一个固定值。电感会随着电流增大而饱和,磁链会随着温度升高而下降,电阻会随着绕组温度变化。所以参数辨识这件事没有“一次到位”的说法,只能持续修正在路线上。
2. 离线参数辨识:上电之前先把底数摸清
2.1 定子电阻:直流注入法背后的线性拟合
离线辨识的第一步永远是测电阻。操作上最简单的方法是直流注入:让电机静止,转子先预定位,然后通过FOC电流环在d轴注入一个恒定电流,q轴给零,等待电流稳定后记录ud和id。
稳态时没有转速,反电动势为零,也没有电流变化,d轴电压方程会简化成:
ud = Rs·id
这时候直接除就得到Rs。听起来很简单,但实际测出来的值经常偏大。原因是逆变器存在死区时间和开关管压降,你从控制算法里读到的ud并不等于真正加在绕组上的电压。偏差可能达到零点几伏,对低电感、小电阻的电机来说非常致命。
我的做法是双点法:用两个不同的id值,比如2A和4A,分别记录稳态ud,然后用两点之间的斜率去算电阻:
Rs = (ud2 - ud1) / (id2 - id1)
这个差分能消掉一部分逆变器非线性带来的电压偏移。如果条件允许,还可以正反两个方向各测一次再平均,进一步消除采样偏置。
这里的通电磁时间要短,否则绕组温升会让电阻漂移。很多不懂的人把电流一直挂着,测出来的电阻已经烫手了,后面所有在线辨识结果全偏。
2.2 电感辨识:锁轴、阶跃与高频小信号
电感不能直接用万用表测,因为电机是三相绕组,而且d轴和q轴在静止坐标下无法区分。最可靠的方法是把转子锁住,然后分别激励d轴和q轴。
对于d轴电感,先把转子预定位到d轴方向,然后给d轴施加一个电压阶跃,同时采集d轴电流的上升曲线。忽略电阻压降的瞬间影响,电流初始阶段的斜率主要由电感决定:
Ld ≈ ud / (did/dt)
需要注意的是,不能只看一个点。实际会有一个电阻压降项,所以更精确的做法是用完整方程:
ud = Rs·id + Ld·(did/dt)
记录多个采样点,用最小二乘同时拟合Rs和Ld。
测q轴电感的时候麻烦一点。q轴电流会出力矩,如果转子没有被机械锁死,电机会转起来。所以必须用锁轴工装,或者用强定位电流让定子磁场把转子“钉住”,然后快速给q轴阶跃电压,在转子还没明显转动前采集iq上升波形。
这里我要提醒一句:电感是强饱和特性的。同一个电机,在2A和10A工况下的Ld可能差30%以上。所以离线测电感时,最好测一条电感随电流变化的曲线,而不要只报一个值。用不同幅值的阶跃电压做多组试验,每个点取一个电感,后期查表用。
另一种很实用的离线方案是高频小信号注入。在锁轴情况下,给电压叠加一个固定频率的正弦波,通过测量电压电流的幅值比和相位差算出阻抗Z = R + jωL,再分离出电感和电阻。这个方法的好处是抗干扰强,坏处是集肤效应会让高频电阻和直流电阻不一样,分离时要小心。
2.3 磁链与反电动势系数:转起来才知道
磁链的本质是永磁体产生的磁通链,它直接决定反电动势。离线辨识磁链最经典的方法是用另一台电机拖着被测电机转,测量被测电机的反电动势。
如果测的是线反电动势峰值E_line,电角速度ωe已知,那么磁链可以这样算:
ψf = E_line / (√3·ωe)
角速度可以通过对拖平台的编码器或者示波器上反电动势频率换算得到。测量时要用示波器直接看电机端子电压,不要经过控制板里的滤波电路,因为滤波器会引入相位和幅值误差。
没有对拖平台也没关系,可以用FOC让电机空载转起来。以id=0控制为例,稳态时q轴电压方程为:
uq = Rs·iq + ωe·ψf
如果已经知道Rs,就可以反解ψf:
ψf = (uq - Rs·iq) / ωe
这个办法依赖Rs精度,所以必须先测好电阻再测磁链。而且如果iq比较大,电阻压降会占很大比重,测量误差会放大。所以我一般让电机空载或者只带很轻的负载来测。
2.4 转动惯量:加减速试验的斜率逻辑
转动惯量影响速度环,离线辨识常用加减速法。核心思想是:给电机一个固定的电磁转矩,让转速线性变化,斜率就等于转矩除以惯量。
先加速再减速的双斜率法可以消除摩擦转矩的影响。假设加速过程电磁转矩为Te_acc,减速过程为Te_dec,转速变化率分别为α1和α2。在摩擦阻力矩基本相同的情况下:
J = Kt·(iq_acc - iq_dec) / (α1 - α2)
其中Kt = 1.5·p·ψf,p是极对数。iq_acc和iq_dec分别是加速段和减速段的q轴电流指令。这个方法比单斜率法准,因为它把摩擦项在两次斜率之间消掉了。
实际操作中,我会让电机在额定转速的30%到70%之间来回扫,每个方向给不同的固定iq,然后用速度曲线的线性区间取斜率。速度环必须处于开环或者弱增益状态,否则速度环会把这些斜坡“吸收”掉,读出来的斜率就失真了。
离线辨识的局限很明显:它测的是常温、特定电流、特定母线电压下的参数。换一个工况,参数就变了。所以离线数据只能当“初始值”,真正的高级用法是让参数在运行中自己更新。
3. 在线参数辨识:让参数跟着工况自己长
3.1 为什么离线数据不够用
我把电机从早上冷机状态跑到中午热机状态做过对比:定子电阻能涨近40%,磁链掉5%左右,电感也会明显变化。如果控制器始终使用早上测的那组参数,会发生什么?
电流环带宽会随着电阻变化而偏离设计值,导致动态响应变差;弱磁控制用的Ld参数不再准确,可能让电流轨迹跑到不安全区域;MTPA角度计算偏了,同转矩下铜耗变大。这些都是在线辨识要解决的问题。
在线辨识的基本思路是:利用电机运行中采集到的电压、电流、转速信号,实时修正参数模型。它不需要停机,不需要额外工装,只要激励足够,就能一直跟踪参数变化。
3.2 递推最小二乘的核心拆解
递推最小二乘是目前工程上最常用的在线辨识方法。它把电机模型改写成“线性回归”的形式:
y = φ^T · θ
其中y是测量到的电压,φ是已知的电流、转速、微分项组成的回归向量,θ就是我们要辨识的参数。拿d轴电压方程举例:
ud = Rs·id + Ld·(did/dt) - ωe·Lq·iq
可以写成:
y = ud φ = [id, did/dt, -ωe·iq]^T θ = [Rs, Ld, Lq]^T
RLS的核心更新公式如下:
K(k) = P(k-1)·φ(k) / (λ + φ^T(k)·P(k-1)·φ(k)) θ(k) = θ(k-1) + K(k)·[y(k) - φ^T(k)·θ(k-1)] P(k) = [P(k-1) - K(k)·φ^T(k)·P(k-1)] / λ
这里的P是协方差矩阵,λ是遗忘因子。遗忘因子一般在0.95到0.99之间,λ越接近1,历史数据权重越大,估计越平滑但跟踪越慢;λ越小,对新数据越敏感但噪声越大。
q轴方程也可以同样整理:
uq = Rs·iq + Lq·(diq/dt) + ωe·Ld·id + ωe·ψf
回归向量就变成:
φ = [iq, diq/dt, ωe·id, ωe]^T θ = [Rs, Lq, Ld, ψf]^T
要注意的是,did/dt和diq/dt是数值微分项,直接差分会把PWM开关噪声放大。我的经验是:先对电流做一阶低通滤波,再计算差分,并且把控制周期Ts固定,否则协方差更新会产生抖动。
RLS最大的陷阱是“持续激励”。如果电机一直在恒速恒流运行,回归向量φ各个元素高度相关,协方差矩阵P会退化,参数估计就不可靠。你可能会看到参数“自嗨式”地乱飘,其实不是算法坏了,而是输入信号信息量不够。解决办法是定期叠加一个幅值很小的PRBS信号或者正弦信号,让电流、转速产生足够多的变化,保证P矩阵不退化。
3.3 扩展卡尔曼滤波与模型参考自适应的取舍
除了RLS,另外两个常见思路是EKF和MRAS。
扩展卡尔曼滤波可以把电机参数当作增广状态放到状态方程里。标准的PMSM电流方程是:
did/dt = (-Rs·id + ωe·Lq·iq + ud) / Ld diq/dt = (-Rs·iq - ωe·Ld·id - ωe·ψf + uq) / Lq
把Rs、Ld、Lq、ψf当成缓慢时变的状态量,构成一个高维状态向量,然后用标准EKF流程做预测和更新。EKF的优点是抗噪能力强,能同时估计状态和参数;缺点是计算量很大,而且需要调Q矩阵和R矩阵。Q矩阵调太大,参数会跟着噪声乱跳;调太小,跟踪温度变化又太慢。我在调EKF时经常用“先离线采集数据、离线算好统计特性、再搬上控制器”的方式,能省很多现场试凑时间。
MRAS则更直观:用一个可调模型输出估计电流,和电机实际反馈电流做差,然后用自适应律去调参数,直到误差消失。它的结构像一个自动跟随系统,实现起来比EKF简单,但对参考模型的准确性要求高。如果模型本身忽略了铁损或电感饱和,MRAS的辨识结果会带系统偏差。
3.4 三种在线方法怎么选
| 方法 | 计算量 | 收敛速度 | 抗干扰能力 | 实现难度 | 典型场景 |
|---|---|---|---|---|---|
| RLS | 低 | 快 | 一般 | 低 | 工业伺服、日常参数跟踪 |
| EKF | 高 | 中 | 强 | 高 | 强噪声、同时做状态估计 |
| MRAS | 中 | 中 | 中 | 中 | 无速度传感器与参数联合估计 |
我个人的选择标准是:如果MCU算力紧张,优先RLS;如果项目本身已经在上EKF做无感控制,那就顺带扩展一个参数状态;如果系统里已经有一个转速观测器,可以考虑MRAS写成自适应律。工程上不需要追求最高级算法,稳定可靠最重要。
4. 代码实现:从离线拟合到在线RLS完整Demo
4.1 离线批量最小二乘脚本
离线辨识阶段,我会把实验数据存成CSV,然后用Python做一次批量最小二乘。先用一组实际采集的模拟数据展示核心逻辑,数据结构假设为:t、ud、uq、id、iq、we。
import numpy as np # 假设 data 是已经读取的二维数组 # 数据列:t, ud, uq, id, iq, we t = data[:, 0] ud = data[:, 1] uq = data[:, 2] id = data[:, 3] iq = data[:, 4] we = data[:, 5] # 计算电流微分 did = np.gradient(id, t) diq = np.gradient(iq, t) # d轴方程:ud = Rs*id + Ld*did - we*Lq*iq X_d = np.column_stack([id, did, -we * iq]) theta_d = np.linalg.lstsq(X_d, ud, rcond=None)[0] Rs_d = theta_d[0] Ld_d = theta_d[1] Lq_d = theta_d[2] # q轴方程:uq = Rs*iq + Lq*diq + we*Ld*id + we*psi_f X_q = np.column_stack([iq, diq, we * id, we]) theta_q = np.linalg.lstsq(X_q, uq, rcond=None)[0] Rs_q = theta_q[0] Lq_q = theta_q[1] Ld_q = theta_q[2] psi_f = theta_q[3] print("Rs = ", (Rs_d + Rs_q) / 2) print("Ld = ", (Ld_d + Ld_q) / 2) print("Lq = ", (Lq_d + Lq_q) / 2) print("psi_f = ", psi_f)这段代码把d轴和q轴方程分别做了最小二乘拟合。d轴方程可以估计Rs、Ld、Lq,q轴方程还能估计ψf。两组结果可能有差异,简单平均或者加权平均都是工程上可用的办法。
要注意np.gradient对噪声很敏感。如果采集数据里电流纹波大,最好先用Savitzky-Golay滤波或者移动平均平滑一下,再算微分。另外,如果回归矩阵的条件数太大,lstsq给出的结果也不可靠。你可以看一下X_d的奇异值分布,如果最小奇异值比最大奇异值小好几个数量级,说明激励不够,要重新做实验,加更丰富的电流变化。
4.2 在线RLS的C语言实现
在线部分我给出一个可以移植到MCU的C代码。这里以d轴方程的三参数RLS为例,实现相对独立,后续可以扩展成q轴四参数。
#define RLS_N 3 typedef struct { float theta[RLS_N]; float P[RLS_N][RLS_N]; float lambda; } RLS; void RLS_Init(RLS *rls, const float *theta0, float lambda) { int i, j; rls->lambda = lambda; for (i = 0; i < RLS_N; i++) { rls->theta[i] = theta0[i]; for (j = 0; j < RLS_N; j++) { rls->P[i][j] = (i == j) ? 100.0f : 0.0f; } } } void RLS_Update(RLS *rls, const float *phi, float y) { float Pphi[RLS_N] = {0}; float K[RLS_N] = {0}; float Pnew[RLS_N][RLS_N]; float den = rls->lambda; float y_est = 0.0f; float err; int i, j, k; // P * phi for (i = 0; i < RLS_N; i++) { for (j = 0; j < RLS_N; j++) { Pphi[i] += rls->P[i][j] * phi[j]; } } // 计算分母,防止除零 for (i = 0; i < RLS_N; i++) { den += phi[i] * Pphi[i]; } if (fabsf(den) < 1e-9f) return; // 卡尔曼增益 for (i = 0; i < RLS_N; i++) { K[i] = Pphi[i] / den; } // 参数更新 for (i = 0; i < RLS_N; i++) { y_est += phi[i] * rls->theta[i]; } err = y - y_est; for (i = 0; i < RLS_N; i++) { rls->theta[i] += K[i] * err; } // 协方差矩阵更新 for (i = 0; i < RLS_N; i++) { for (j = 0; j < RLS_N; j++) { float sum = 0.0f; for (k = 0; k < RLS_N; k++) { sum += K[i] * phi[k] * rls->P[k][j]; } Pnew[i][j] = (rls->P[i][j] - sum) / rls->lambda; } } for (i = 0; i < RLS_N; i++) { for (j = 0; j < RLS_N; j++) { rls->P[i][j] = Pnew[i][j]; } } }这个结构体在每次PWM中断里调用一次。调用前把phi填好,y填当前采样电压,然后执行RLS_Update。P矩阵初始化用的100,适合参数未知系统。如果已经有一个靠谱的初值,可以初始化为更小的数,收敛会更快。
实际项目中,我不建议直接把theta输出给控制环。最稳的做法是再做一层低通滤波:theta_used = theta_used·α + theta_new·(1-α),α取0.9以上。这样即使辨识结果在某一个控制周期出现跳变,也不会直接冲击电流环。
4.3 辨识出来的参数如何反哺控制器
参数辨识本身不是目的,让控制器用上准确参数才是目的。
电流环PI整定是最直接的受益点。如果辨识到L=1.2mH,Rs=0.35Ω,设计带宽ωc=1000rad/s,那么连续域的经典配置是:
Kp = L·ωc = 1.2e-3 × 1000 = 1.2 Ki = Rs·ωc = 0.35 × 1000 = 350
这个配置的核心思想是让PI零点去对消电机模型的极点。如果参数不准,Kp和Ki配比就会偏离,电流环动态和稳态都会出问题。
弱磁控制更需要Ld和Lq。弱磁电流的计算依赖Ld和磁链,如果这两个参数偏差大,高速区域的电压会提前饱和,可能引发过流或者转矩抖动。磁链参数则直接影响转矩估算和MTPA角度,对转矩精度要求高的场合尤其敏感。
转动惯量辨识结果用来整定速度环。惯量大,速度环增益不能太高,否则机械系统会振荡;惯量小,增益可以上去,响应更快。用辨识值代替粗调值,能省下大量试参数时间。
4.4 参数切换的保护机制
在线辨识值随时在变,如果每算出一个新值就立刻替换当前控制参数,风险非常大。可能一个电流尖峰就导致辨识值跳变,电流环突然振荡。
我习惯加三道保护:
- 范围限制:每个参数只允许在一个合理区间内变化,比如Rs只能在初始值50%到150%之间,超出就截断。
- 变化率限幅:单次更新最大变化量限制住,例如每次调用最多变化0.01,超过就取最大值。
- 激励检测:持续统计φ向量的能量,如果能量过低,说明信号不够丰富,直接冻结本次更新。
P矩阵也需要做上限管理。遗忘因子小于1时,P矩阵理论上可以无限增长,数值会膨胀到float溢出的边缘。我每隔一段时间检查P的对角线,如果超过阈值就统一缩放,或者强制降低到初始值。
5. 现场问题排查与避坑手册
5.1 辨识结果不准的几类典型原因
实操中参数不准,十有八九不是算法问题,而是输入数据有问题。我整理了一张速查表,基本覆盖了常见情况。
| 现象 | 可能原因 | 检查方法 |
|---|---|---|
| Rs偏大 | 死区时间未补偿、管压降未考虑 | 用双点差分法,增大电流差 |
| Ld偏小 | 电流微分噪声大、电压采样滞后 | 先滤波再微分,检查采样时序 |
| ψf偏大 | 编码器零位偏移、电压幅值偏大 | 重新校零,比对反电动势波形 |
| Lq与Ld相差过大 | 转子在测电感时没有锁死 | 检查锁轴工装或强定位电流 |
| J偏大 | 加减速斜率窗口取太大 | 截取转速线性段,排除静差段 |
| 所有参数飘忽不定 | 母线电压波动、电流采样偏置 | 同步采样母线电压,做电流零偏校准 |
最容易被忽视的是电流采样偏置。一个0.05A的偏置在低压大电流系统里可能造成百分之几的电压方程误差,最终让电阻辨识值明显偏移。每次实验前,先给DSP置零电流校准,再做辨识实验。
5.2 在线辨识发散与“假收敛”的应急处理
在线RLS最常见的两个故障是发散射和假收敛。发散射表现为某个参数在短时间内冲到极限,然后整个控制环崩溃。这种一般是P矩阵膨胀导致的,按前面说的上限管理就能压住。
假收敛更隐蔽。参数估计误差很小,但四个参数都是错的。比如d轴方程里,Rs多估和Lq少估可能恰好让电压误差抵消。这时候最小二乘损失函数很小,但参数毫无意义。对付假收敛只有一个思路:增加激励维度。叠一个PRBS信号,或者让电机交替在不同电流下运行,让方程组各列不再近似线性相关。
如果现场不允许乱加扰动,还有一个办法是对参数做物理约束。Ld必须大于等于某个值、Lq不能超过某个上限、ψf必须在一个窄范围内。用投影法把RLS的输出限制在物理可行域,即使某一次更新偏了,也只能在边界内抖动。
5.3 几个提升辨识稳定性的实操习惯
我长期做电机驱动,养成了几个和辨识直接相关的习惯,对项目帮助很大。
采样时间必须和PWM中心对齐。电流在开关管导通和关断瞬间有大量尖峰,如果ADC触发点不在PWM中心,采到的电流就带纹波,最后都会折算成辨识误差。电压指令最好从调制波重建,不要直接用DAC采样电压,因为滤波电容会拖慢信号。
数据用于辨识前先过一遍低通。我常用一阶低通,截止频率设置在控制系统带宽的3到5倍,再算微分。这样微分项不会把开关频率噪声放大。
激励信号要小而丰富。小是指幅值在安全范围内,不产生明显噪声和发热;丰富是指频率成分多,阶跃只有一种频率,PRBS或多频正弦组合效果好得多。
最后,辨识全程记录温度和母线电压。现场复盘的时候,没有温度数据你根本分不清参数变化到底是算法问题还是工况变化。这个习惯帮我排除过很多假故障。
永磁同步电机参数辨识这件事,做完离线和在线两套,才算是完整闭环。先离线拿到一个靠谱的静态初值,再在线跟随温度和工况变化,最后把修正后的参数平滑地交给电流环、速度环和弱磁模块。只有这样,控制器才算真正“认识”它所驱动的电机。
我最终的建议是:不要迷信任何一种辨识算法,RLS够用时别硬上EKF;更不要让辨识结果直接裸奔进控制环,平滑和保护机制必须做到位。参数辨识不是万能的,但没有它,FOC的高性能永远只是一句空话。带着这套流程去现场,你会少踩很多坑。