Modelica车用PMSM电驱仿真:从dq建模到参数辨识与能量守恒校验
2026/9/18 15:09:39 网站建设 项目流程

简介:这篇发表于《微电机》2011年第11期的技术论文,面向从事新能源汽车电驱动系统建模与仿真的工程师及高校研究者,聚焦纯电动汽车多领域耦合系统的统一建模难题。文中以永磁同步电机为对象,介绍Modelica多领域建模语言与Dymola仿真平台的基本特点,给出永磁同步电机d-q轴数学模型、电压与磁链方程及电磁转矩、机械运动方程的推导思路,并说明如何结合电机及驱动系统台架测试数据校正模型参数,再通过实验纯电动汽车整车仿真验证模型精度,仿真结果与台架测试接近,同时讨论了现有数值模型在整车性能评价中的不足与改进方向。包内为单个PDF文件,约317KB,篇幅紧凑,便于快速检索与引用,适合电机控制、整车仿真方向的读者作为参考文献。目前已有138人学习。

1. 从电机台架上那个「一改参数就炸」的时刻说起

做纯电动汽车电驱仿真的人大概都碰过这类事:把一台 150 kW 永磁同步电机的参数填进某个黑盒电机模块,稳态波形跑得挺好,一旦把母线电压、逆变器和整车质量放进同一张图,转速环开始抖,转矩冒高频毛刺,求解器直接报步长过小停下。问题通常不在电机本身,而在「谁给谁供电压、谁又反过来决定电流」这层耦合被拆到了不同工具里。Modelica 把电机、驱动电路、减速器和整车纵向动力学都写成方程,用连接器自动配平,符号系统统一处理耦合。这篇讲的是怎么从 dq 轴方程一路搭到工况仿真:库组件怎么选、参数怎么填、仿真发散了怎么定位、参数辨识怎么接。

2. Modelica 侧的车用 PMSM 建模:从 dq 方程到库组件参数

2.1 车用 PMSM 的四个方程和那条功率公式

先立方程,不然后面填参数只能靠猜。在转子磁场定向的 dq 坐标系下,车用永磁同步电机的定子电压方程写成:

ud = Rs·id + Ld·did/dt − ωe·Lq·iq uq = Rs·iq + Lq·diq/dt + ωe·(Ld·id + ψf)

其中ωe = p·ωm是电角速度,p是极对数,ωm是机械角速度。电磁转矩按

Te = 1.5·p·[ψf·iq + (Ld − Lq)·id·iq]

展开,前一项是永磁转矩,后一项是磁阻转矩。内置式转子Lq > Ld,磁阻转矩为正,所以低速大转矩工况常把id往负方向拉;表贴式转子Ld ≈ Lq,磁阻项近似为零,控制上就退化成纯iq给转矩。

机械侧是

J·dωm/dt = Te − TL − B·ωm

再看那条常被搜索的「永磁同步电机的功率公式」。电磁功率用 dq 量表示是

Pe = 1.5·(ud·id + uq·iq)

稳态下忽略铜耗,它约等于Te·ωm。这两个式子后面会拿来做能量守恒校验——Modelica 的好处正在这里,你可以在模型里同时定义PeTe·ωm,让求解器自己暴露出两者对不上的时刻,而不是靠人去推。

需要区分一下:这套 dq 方程适用于正弦波驱动的 PMSM。如果手头模型是六步换相那种方波驱动,反电动势不是正弦,dq 变换的前提就不成立,得换回 abc 三相时域方程来描述。同样一套 dq 模型,做并网仿真时边界条件是电网电压定向和低电压穿越,做车用时边界条件换成了母线电压随 SOC 跌落和宽调速范围,方程一样,外边界完全不同。

2.2 Modelica.Electrical.Machines 里的组件选型和参数表

Modelica 标准库(MSL)里直接有现成的永磁同步电机组件,路径是Modelica.Electrical.Machines.BasicMachines.SynchronousMachines.SM_PermanentMagnet,配套还有Modelica.Electrical.Machines.Utilities.TerminalBox负责星形/三角形接线,以及Modelica.Electrical.PowerConverters里的两电平逆变器组件。选型逻辑很直接:拿库里的 dq 模型当被控对象,把控制算法自己写,这样中间每一步电压、电流、角度都可见。

参数含义车用 150 kW 级典型取值填错的后果
p极对数4电角速度整体错倍,转矩直接差一个系数
fsNominal额定电频率300 Hz(对应基速 4500 r/min)影响库内部标幺化基准,影响损耗计算
Rs定子相电阻0.012 Ω @20 °C低速铜耗偏小、电流环增益失配
Ldd 轴电感0.25 mHid响应偏慢,弱磁区算不准
Lqq 轴电感0.55 mH磁阻转矩错,峰值转矩对不上台架
ψf永磁磁链0.09 Wb反电动势整体偏差,电压利用率算错
Js转动惯量0.05 kg·m²转速环阶跃响应快慢失真

有一点要提醒:不同 MSL 版本对磁链参数的命名可能是phi_fPhi_f或归到别的组件属性里,useDamperCage这类开关也存在版本差异。

提示:填参数前先打开本地库的组件文档,按你安装的那一版的接口名来写,不要照抄别人博客里的字段名。

再验一下这套参数的合理性。极对数 4、基速 4500 r/min 对应电频率 300 Hz,电角速度ωe = 2π×300 ≈ 1885 rad/s,反电动势幅值ωe·ψf ≈ 169.6 V(相电压峰值)。母线 350 V 左右时基速点还有调节余量,说明这套数不是瞎凑的。峰值转矩 300 N·m 需要iq ≈ 300 / (1.5×4×0.09) ≈ 555 A,属于车用电机正常电流量级。

2.3 整车侧:把车轮阻力折算到电机轴

电机的负载不是恒定的,它来自整车。纵向动力学写成

m·dv/dt = Ftraction − Froll − Faero − Fgrade Froll = m·g·f·cosθ, Faero = 0.5·ρ·Cd·A·v², Fgrade = m·g·sinθ

牵引力由电机转矩经减速比i和车轮半径r折算:Ftraction = Te·i·η / r。反过来,折算到电机轴上的负载转矩是TL = (Froll + Faero + Fgrade)·r / (i·η),转子侧惯量按Jeq = Jmotor + m·r² / i²折算。

这一步在 Modelica 里的意义是:你不需要手算折算后的TL曲线再喂给电机,而是把整车方程和电机方程写在同一个模型里,mCdA、坡度这些量改一个,整条链路自动跟着变。这也是从「电机仿真」跨到「纯电动汽车仿真」的分界线。

3. 动手:在 Modelica 里搭一个能跑的 PMSM 驱动仿真

3.1 环境准备与最小可运行模型

环境准备很朴素:Windows 下装 OpenModelica 官方安装包,Linux 下用系统包管理器装,装完确认omc在 PATH 里,omc --version能打出东西就行。Dymola 属于商业工具,命令行风格不同但组件库是同一套 MSL。

最小可运行模型只保留电机本体、端子盒、恒转矩负载三块:

model PMSM_Drive_Minimal "150 kW 车用 PMSM 最小驱动仿真" // ---- 电机本体:MSL 中的永磁同步电机组件 ---- Modelica.Electrical.Machines.BasicMachines.SynchronousMachines.SM_PermanentMagnet motor( p = 4, // 极对数 fsNominal = 300, // 额定电频率 Hz,对应基速 4500 r/min Rs = 0.012, // 20 °C 下定子相电阻 Ω Ld = 0.25e-3, // d 轴电感 H Lq = 0.55e-3, // q 轴电感 H Js = 0.05); // 转动惯量 kg·m2 // ---- 三相端子盒:星形接法 ---- Modelica.Electrical.Machines.Utilities.TerminalBox terminalBox(terminalConnection = "Y"); // ---- 负载侧:恒转矩 + 惯量,对应整车折算后的阻力 ---- Modelica.Mechanics.Rotational.Sources.Torque loadTorque; Modelica.Blocks.Sources.Constant tLoad(k = 50); equation connect(terminalBox.plug_sn, motor.plug_sn); connect(terminalBox.plug_sp, motor.plug_sp); connect(motor.flange, loadTorque.flange); connect(tLoad.y, loadTorque.tau); end PMSM_Drive_Minimal;

逻辑说明:motor是被控对象,内部已经用 dq 方程实现了SM_PermanentMagnetterminalBox把三个绕组端子聚成一组可对接逆变器的接口;loadTorque提供一个恒定的反作用转矩,tLoadk就是从整车式子里算出来的TL初值。连接器plug_sn/plug_sp/flange都是 MSL 约定的标准接口,只要类型一致,connect就能自动写出守恒方程。

这个模型还没接逆变器和控制,属于开环空载,跑通它只是为了确认参数能编译、初值能给。

3.2 d/q 轴电流环:PI 增益怎么算、解耦怎么加

控制部分自己写一个模型,输入是idRefiqRefidMeaiqMea、电角速度,输出是uduq

model FOC_CurrentLoop "d/q 轴电流环,含交叉耦合前馈" parameter Real Ld = 0.25e-3; parameter Real Lq = 0.55e-3; parameter Real Rs = 0.012; parameter Real psi_f = 0.09; parameter Real wBW = 2*Modelica.Constants.pi*500 "电流环带宽 rad/s"; Modelica.Blocks.Interfaces.RealInput idRef; Modelica.Blocks.Interfaces.RealInput iqRef; Modelica.Blocks.Interfaces.RealInput idMea; Modelica.Blocks.Interfaces.RealInput iqMea; Modelica.Blocks.Interfaces.RealInput wElec "电角速度 rad/s"; Modelica.Blocks.Interfaces.RealOutput ud; Modelica.Blocks.Interfaces.RealOutput uq; Real eiD "d 轴积分状态"; Real eiQ "q 轴积分状态"; equation der(eiD) = idRef - idMea; der(eiQ) = iqRef - iqMea; // 前馈项把 -we*Lq*iq 和 +we*(Ld*id + psi_f) 补掉 ud = Ld*wBW*(idRef - idMea) + Rs*wBW*eiD - wElec*Lq*iqMea; uq = Lq*wBW*(iqRef - iqMea) + Rs*wBW*eiQ + wElec*(Ld*idMea + psi_f); end FOC_CurrentLoop;

增益不是拍脑袋来的。按内模整定,比例增益取Kp = L·ωbw,积分增益取Ki = Rs·ωbw,其中ωbw是电流环带宽。取带宽 500 Hz,得到Kp_d ≈ 0.785Ki_d ≈ 37.7(对应 d 轴),Kp_q ≈ 1.73Ki_q ≈ 37.7(对应 q 轴)。因为LqLd大,q 轴的比例增益必须比 d 轴大,两根轴用同一组 PI 参数是新手最常见的错。

后两项是交叉耦合前馈。电机在高速时ωe·Lq·iqωe·Ld·id这两项会很大,纯靠积分去补会拖慢电流响应,把耦合项直接前馈抵掉,电流环就退化成一个简单的一阶系统。注意前馈里的ψf项,它对应反电动势,如果漏掉,q 轴稳态误差会随转速线性增大。

另外要提醒的是,这里的idMeaiqMea需要先通过 Park 变换从三相电流得到,Park 变换用的角度必须是p·θm而不是θm。转子转角直接乘极对数,这是另一个高频错误点。

3.3 工况注入与求解器参数配置

工况注入可以用 MSL 的CombiTimeTable组件,把 NEDC 或 WLTC 的目标车速按时间表填进table,配合 2.3 节的整车方程反算出目标转矩,再经转速环转成iqRef。如果只是想验证控制逻辑,直接给iqRef一个阶跃或斜坡也可以。

求解器配置才是真正影响成败的部分:

# OpenModelica:先编译成可执行文件 omc PMSM_Drive_Minimal.mo # 再按需覆盖运行时参数 ./PMSM_Drive_Minimal -s=dassl -tolerance=1e-6 -stopTime=10 -stepSize=1e-4 -r=pmsm.mat

参数含义:-s选求解器,用dassl处理带事件的刚性系统;-tolerance是局部误差容差,电机模型建议从1e-6起试;-stopTime是终止时间;-stepSize是输出步长,不是积分步长;-r是结果文件。OpenModelica 不同版本的命令行开关略有出入,下手前先omc --help确认。

如果模型里带 10 kHz 的 PWM 开关,仿真负债会陡增,这时候可以考虑两种折中:一是用平均值模型替代开关模型,把逆变器输出直接写成等效相电压,牺牲开关纹波换速度;二是保留开关模型但限制最大步长到开关周期的十分之一以内。前者适合做整车级能量核算,后者适合看电流纹波和开关损耗。

4. 仿真发散和精度不对:Modelica 电机仿真的排查顺序

4.1 五类典型症状和对因表

仿真发散在 Modelica 里的表现形式很集中,按症状查比乱改参数快得多:

症状常见原因处理方向
t=0 就报奇异或无解初始化方程不完整,状态初值互相冲突initial equation补方程,或固定关键状态初值
波形出现高频锯齿并快速发散PWM 事件密集 + 容差过松收紧tolerance,限制最大步长,或换平均值模型
转子位置与电流相位明显错位Park 变换角度用了机械角改回p·θm,检查角度基准
转速缓慢漂移不收敛负载转矩或摩擦系数符号方向错核对Torque的正方向约定和B的符号
波形看着正常但能量不守恒损耗项被忽略或重复计入补铜耗、铁耗定义,核对PeTe·ωm

按这个顺序往下查,比逐行读代码效率高。第一类和第四类通常十分钟能解决,第三类如果模型是自己搭的,八成还会连带发现坐标变换顺序写反了。

4.2 初始化与代数环:从高阶 DAE 降指标的实操

Modelica 模型本质是微分代数方程,求解器启动时要先把代数变量解出来,指标过高或者初值不自洽,求解器就报奇异。车用 PMSM 模型里最容易出问题的是转子静止起动瞬间——转速为零,但反电动势项和耦合项都以转速为系数,形式上退化了。

一个实用的初始化写法:

initial equation // 静止起动:转速初值 0,转子机械角初值 0 // 变量名以本地 MSL 版本中 SM_PermanentMagnet 的接口为准 der(motor.wMechanical) = 0; // 起动瞬间角加速度为 0 motor.wMechanical = 0;

逻辑是:先把机械侧锁住,再让电气侧从零电流开始,避免求解器去解一个「转速为零但转矩非零」的矛盾初值。

代数环的处理原则是「能解析化就解析化」。比如电流环里的ud依赖iq,而iq又由ud经电机方程算出来,如果这两者中间没有积分环节隔开,就构成代数环。办法是把电流环的积分器保留在反馈通道里,让ud由积分状态和输入直接写出,而不是反过来解方程。上面FOC_CurrentLoopder(eiD)der(eiQ)先出现、uduq后写,就是为了保证这个顺序。

注意:改完初始化方程要重新跑一遍零时刻附近的波形,而不要只看稳态结果。初始化的错往往在 t<0.01 s 就暴露完了。

4.3 用仿真数据反推 Rs、Ld、Lq、ψf

参数辨识和仿真是互相喂养的关系:仿真给辨识提供激励充分的数据,辨识给仿真校准模型参数。稳态下 dq 方程里的微分项为零,退化成

ud = Rs·id − ωe·Lq·iq uq = Rs·iq + ωe·(Ld·id + ψf)

RsLqLdψf当成四个未知量,每个采样点贡献两个方程,做线性最小二乘就能解:

import numpy as np import pandas as pd # 1. 读 Modelica 导出的 csv(列名按实际导出结果调整) df = pd.read_csv("pmsm_log.csv") id_, iq_ = df["id"].to_numpy(), df["iq"].to_numpy() ud_, uq_ = df["ud"].to_numpy(), df["uq"].to_numpy() we_ = df["we"].to_numpy() # 电角速度 rad/s # 2. 组装 A·theta = b,theta = [Rs, Lq, Ld, psi_f] n = len(df) A = np.zeros((2 * n, 4)) b = np.zeros(2 * n) A[:n, 0] = id_ # ud 方程里的 Rs 项 A[:n, 1] = -we_ * iq_ # ud 方程里的 Lq 项 b[:n] = ud_ A[n:, 0] = iq_ # uq 方程里的 Rs 项 A[n:, 2] = we_ * id_ # uq 方程里的 Ld 项 A[n:, 3] = we_ # uq 方程里的 psi_f 项 b[n:] = uq_ # 3. 最小二乘求解 theta, *_ = np.linalg.lstsq(A, b, rcond=None) Rs_hat, Lq_hat, Ld_hat, psi_hat = theta print(f"Rs={Rs_hat:.5f} Ω, Lq={Lq_hat*1e3:.4f} mH, " f"Ld={Ld_hat*1e3:.4f} mH, psi_f={psi_hat:.5f} Wb")

几个必须注意的点。第一,这种线性回归只在稳态成立,所以要先从仿真结果里截取转速和电流都稳定的时间段,阶跃瞬间的数据必须剔除,否则did/dtdiq/dt被当成零会带来系统性偏差。第二,idiqwe之间如果存在共线性(比如一直在同一个转速下跑),Ldψf会分不开,激励里必须包含多个转速点。第三,想要动态工况下的参数,得换成递推最小二乘或扩展卡尔曼滤波,那套代码要维护协方差矩阵,复杂度上一个台阶。

5. 进阶:外特性扫描与能量守恒校验

5.1 转矩-转速外特性批量扫描

单个工况点跑通之后,下一步是把工作点铺开。裸手改参数跑几十次不现实,用脚本驱动仿真程序批量覆盖更实际:

import subprocess # 遍历转速点,每点锁定转速、扫电流幅值,找能达到的最大转矩 for n_rpm in [1000, 3000, 4500, 6000, 9000, 12000]: we = 4 * n_rpm * 2 * 3.14159265 / 60 # 电角速度 for id_frac in [-0.3, -0.15, 0.0, 0.15, 0.3]: # 弱磁电流分配比例 tag = f"n{n_rpm}_id{int(id_frac*100)}" subprocess.run([ "./PMSM_Drive_Minimal", f"-override=control.wBW=3141.59,control.idFrac={id_frac}", f"-stopTime=2", "-tolerance=1e-6", f"-r=out_{tag}.mat" ], check=True)

说明:-override用来覆盖模型里的参数,路径写成「组件名.参数名」的形式;内层循环扫id分配比例,就是在试不同的弱磁程度。跑完把每个转速点下的最大转矩画出来,得到的就是外特性曲线。这条路比在图形界面里手动点一百次靠谱,也方便进版本管理。

判断曲线是否合理,可以看三个特征点:基速点附近转矩应保持恒定;进入弱磁区后转矩随转速近似按1/ωm衰减;最高转速点的电压利用率接近母线电压上限。

5.2 能量守恒校验:让模型自己证明自己

外特性扫完之后,最有用的一步校验是能量守恒。在模型里把三个功率量都显式定义出来:

pElec = 1.5*(ud*id + uq*iq) // 电磁功率 pMech = Te * wMechanical // 机械功率 pLoss = 1.5*Rs*(id^2 + iq^2) // 定子铜耗

然后在结果里核对pElec ≈ pMech + pLoss。稳态下这条式子的残差应该落在数值容差量级,如果残差是百分之几甚至更大,一般说明三件事之一:转动惯量或摩擦系数填错导致机械侧吸收了能量;损耗项漏掉了铁耗,高速时这个缺口会随转速放大;Te的计算里用了机械角速度而不是电角速度去算功率。

校验项期望关系残差偏大时的排查
电气-机械功率平衡pElec ≈ pMech + pLoss先查Te定义,再查摩擦和惯量
转矩-电流关系Te ≈ 1.5·p·(ψf·iq + (Ld−Lq)·id·iq)LdLq是否填反,id符号是否搞错
反电动势-转速关系E ≈ ωe·ψfpψf,这两个参数最容易抄错一位

一个小技巧:把这些校验关系直接写成模型里的方程,而不是事后用 Python 算。Modelica 的求解器会在时间推进过程中持续检查这些等式,一旦哪一步不满足就报残差,比人翻波形快得多。这也是把 Modelica 用来做车用电驱仿真的核心价值——模型里的每一条物理关系都可以被显式地验证,而不是藏在一个黑盒模块里。

本文还有配套的精品资源,点击获取

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

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

立即咨询