4. PMSM电机模型实现:用Python实现电机电气方程与机械方程

好,咱们进入正题。

上一章我们聊了软件在环仿真的整体框架,这一章我带你亲手把PMSM的数学模型变成能跑的Python代码。说实话,电机模型是整个仿真系统的基石——模型不准,后面做啥控制都是白搭。我在项目里吃过这个亏,所以今天咱们把电气方程和机械方程拆开了揉碎了讲。

4.1 为什么是PMSM?

永磁同步电机(PMSM)现在太常见了。电动汽车、伺服驱动、机器人关节,到处都有它的影子。它的特点是:转子是永磁体,没有励磁绕组,所以效率高、功率密度大。

但它的数学模型比直流电机复杂不少。你想想看,三相交流电进去,转子还在转,这中间有坐标变换、有反电动势、有磁链耦合。嗯,咱们一步步来。

4.2 电气方程:dq坐标系下的电压方程

我个人习惯用dq坐标系来建模。为什么?因为把交流量变成了直流量,控制起来方便多了。Park变换和Clark变换是基本功,这里不展开,直接给结论。

在dq旋转坐标系下,PMSM的电压方程长这样:

v_d = R_s * i_d + L_d * di_d/dt - ω_e * L_q * i_q
v_q = R_s * i_q + L_q * di_q/dt + ω_e * (L_d * i_d + ψ_f)

其中:

  • v_d, v_q — d轴和q轴电压
  • i_d, i_q — d轴和q轴电流
  • R_s — 定子电阻
  • L_d, L_q — d轴和q轴电感
  • ω_e — 电角速度
  • ψ_f — 永磁体磁链

关键点:这里的ω_e是电角速度,不是机械角速度。两者差一个极对数:ω_e = p * ω_m。我刚开始做仿真时经常搞混,结果出来的转速曲线怎么看怎么不对。

4.3 机械方程:转起来靠它

电机不光有电,还有机械运动。机械方程描述的是转矩和转速的关系:

J * dω_m/dt = T_e - T_L - B * ω_m

参数说明:

  • J — 转动惯量
  • ω_m — 机械角速度
  • T_e — 电磁转矩
  • T_L — 负载转矩
  • B — 阻尼系数

电磁转矩的计算公式:

T_e = 1.5 * p * (ψ_f * i_q + (L_d - L_q) * i_d * i_q)

对于表贴式PMSM(SPMSM),L_d = L_q,公式简化为:

T_e = 1.5 * p * ψ_f * i_q

说白了,转矩和q轴电流成正比。这也是为什么我们做矢量控制时,主要控制i_q的原因。

4.4 Python实现:从方程到代码

好,理论讲完了,咱们动手写代码。我习惯用面向对象的方式封装电机模型,这样后面做仿真时调用起来方便。

import numpy as np

class PMSM:
    def __init__(self, params):
        # 电气参数
        self.Rs = params['Rs']          # 定子电阻
        self.Ld = params['Ld']          # d轴电感
        self.Lq = params['Lq']          # q轴电感
        self.psi_f = params['psi_f']    # 永磁体磁链
        self.p = params['p']            # 极对数
        
        # 机械参数
        self.J = params['J']            # 转动惯量
        self.B = params['B']            # 阻尼系数
        
        # 状态变量
        self.id = 0.0
        self.iq = 0.0
        self.omega_m = 0.0
        self.theta_m = 0.0
        
    def update(self, vd, vq, TL, dt):
        """
        更新电机状态
        vd, vq: dq轴电压
        TL: 负载转矩
        dt: 仿真步长
        """
        # 电角速度
        omega_e = self.p * self.omega_m
        
        # 电流微分方程(电气方程)
        did_dt = (vd - self.Rs * self.id + omega_e * self.Lq * self.iq) / self.Ld
        diq_dt = (vq - self.Rs * self.iq - omega_e * (self.Ld * self.id + self.psi_f)) / self.Lq
        
        # 更新电流
        self.id += did_dt * dt
        self.iq += diq_dt * dt
        
        # 电磁转矩
        Te = 1.5 * self.p * (self.psi_f * self.iq + (self.Ld - self.Lq) * self.id * self.iq)
        
        # 机械方程
        domega_dt = (Te - TL - self.B * self.omega_m) / self.J
        
        # 更新转速和位置
        self.omega_m += domega_dt * dt
        self.theta_m += self.omega_m * dt
        
        return self.id, self.iq, self.omega_m, self.theta_m

我的小技巧:仿真步长dt不要设太大。我一般用1e-5到1e-4秒。步长太大,数值积分会发散,结果直接飞掉。步长太小,仿真跑得慢。你根据实际需求折中一下。

4.5 验证模型:跑一个空载启动

模型写好了,得验证一下。咱们来个最简单的场景:电机空载启动,看看转速响应。

# 电机参数
params = {
    'Rs': 0.958,      # 欧姆
    'Ld': 0.00525,    # 亨利
    'Lq': 0.00525,    # 亨利(表贴式)
    'psi_f': 0.1827,  # 韦伯
    'p': 4,           # 极对数
    'J': 0.003,       # kg·m²
    'B': 0.0001       # N·m·s/rad
}

motor = PMSM(params)

# 仿真参数
dt = 1e-5
total_time = 0.5
steps = int(total_time / dt)

# 给定电压(开环)
vd = 10.0
vq = 10.0
TL = 0.0

# 记录数据
time = []
speed = []

for i in range(steps):
    id, iq, omega_m, theta_m = motor.update(vd, vq, TL, dt)
    if i % 1000 == 0:  # 每1000步记录一次
        time.append(i * dt)
        speed.append(omega_m * 60 / (2 * np.pi))  # 转成RPM

# 打印最终转速
print(f"最终转速: {speed[-1]:.2f} RPM")

注意:开环启动时,如果电压给得太猛,电流会很大。我曾经有一次忘了限制电压,结果仿真电流飙到几百安培,虽然不会烧硬件,但仿真结果完全失真。建议加个电流限幅。

4.6 模型扩展:考虑饱和与温度

实际电机不是理想模型。温度高了,电阻会变大。电流大了,电感会饱和。如果你要做高精度仿真,这些都得考虑。

我常用的做法是:

  • 电阻温度修正:R_s(T) = R_s0 * (1 + α * (T - T0))
  • 电感饱和:查表法,根据i_d, i_q查对应的L_d, L_q
  • 磁链变化:温度升高,永磁体磁链会下降

这些扩展不难,就是在update()函数里加几个查表或计算步骤。但要注意,查表会拖慢仿真速度。如果你做实时仿真,得权衡一下精度和速度。

4.7 常见坑点总结

最后,我把自己踩过的坑列出来,你写代码时注意一下:

  1. 符号搞反:电压方程里ω_e * L_q * i_q的符号,不同教材可能不一样。你得根据自己定义的dq轴方向来确认。
  2. 单位换算:电角速度和机械角速度别搞混。我见过有人直接用机械角速度算反电动势,结果模型完全不对。
  3. 数值稳定性:欧拉法简单,但步长大了容易发散。如果发现仿真结果震荡,试试减小步长,或者改用龙格-库塔法。
  4. 初始条件:电机启动时电流为0,但如果你直接给一个阶跃电压,电流会跳变。建议加个软启动,让电压慢慢上升。

好了,这一章的内容就到这。你把这个PMSM模型跑通了,后面做电流环、速度环仿真就有基础了。下一章咱们聊怎么用这个模型做闭环控制仿真。