ARTICLE · 1203702
电控软件工程师拆解:汽车电机FOC算法,坐标变换该如何落地

电控软件工程师拆解:汽车电机FOC算法,坐标变换该如何落地
上个月有个做新能源乘用车电控的兄弟找我,说他把一套FOC代码移植到新平台上,电机是能转,可低速抖得跟筛子似的,扭矩纹波大到他自己都不好意思上台架。他把PI参数翻来覆去调了三遍,增益从0.5拧到2.0,半点用没有。最后我让他干一件事——把转子锁死,手动给θ角从0扫到360度,盯着Id和Iq的波形看。结果Id根本不是一条直线,跟着θ在那儿正余弦地抖。
问题压根不在PI环,在坐标变换那一层。
这种事我见得太多了。大部分人学FOC,注意力全砸在PI参数怎么调、SVPWM怎么发波上,偏偏把最基础的Clarke和Park变换当成两行公式,抄进代码就完事。可你真到项目里,电机转不转得起来、扭矩平不平顺、低速有没有异响,十有八九卡在坐标变换和角度同步这两个地方。
今天这篇不跟你推公式了——公式教科书上有的是。我就聊一件事:这两个变换,落到DSP或者MCU的代码里,到底该怎么写,哪些地方最容易踩坑,踩了坑怎么第一时间揪出来。
01 先想清楚:我们为什么非要做坐标变换
很多人背得出来Clarke和Park长什么样,你要反问他一句"我直接在三相静止坐标系下控Ia、Ib、Ic不行吗",他大概率愣一下。
我用大白话讲。三相电机的绕组在空间上差120度,你往里头通三相交流电,转子就被拖着转。问题是——你想让电机出多少扭矩,你到底得控制三相电流里的什么东西?你会发现Ia、Ib、Ic这三个量是强耦合的,而且跟着转子位置在时间上不停变化。你在A相上做个PID,B相C相跟着乱套。这就像你开一辆方向盘和车轮之间没有固定角度的车,你根本不知道现在该打多少。
Clarke变换干的事,是把三个相量投到一个二维平面上。三相变两相,信息一点没丢——因为三相电流加起来等于零,本来就只有两个自由度。这个二维平面是固定不动的,我们叫它αβ静止坐标系。
这还没完。在αβ坐标系下,电流还是交流的——转子在转,你看到的电流波形是个旋转的矢量。你拿一个直流PID去追一个正弦波,怎么追都有稳态误差,这是控制原理决定的,跟你PI调得好不好没关系。
这时候Park变换出场了。它让你把坐标系跟着转子一起转。转子转多少度,你的坐标系就跟着转多少度。这么一来,转子磁场方向上的电流Id,和垂直方向上的电流Iq,就变成了两个直流量。Id管励磁,Iq管扭矩。你想让电机出多大扭矩,就给Iq一个目标值,PI闭环跟着就完事。表贴式永磁同步电机Id默认给零,要弱磁的时候再给个负的Id。

说白了,坐标变换的全部意义,就是把一个又耦合又交流的电机模型,降维成一个他励直流电机模型。你在dq轴上看到的东西越干净,你的电流环就越好调。
但这里有个硬前提——你那个跟着转子转的坐标系的角度θ,必须跟真实的转子位置严丝合缝。θ偏了,后面那一堆PI、SVPWM全白搭。
02 Clarke变换:别只盯着2/3这个系数
先写公式。三相电流满足Ia+Ib+Ic=0,Clarke变换之后是这样的:
Iα = Ia
Iβ = (Ia + 2·Ib) / √3
代码里你大概会写成:
Ialpha = Ia;Ibeta = (Ia + 2.0f * Ib) * 0.57735027f;
就这么两行。但就这两行,我见过至少三种写错的方式。
第一种,系数用错。教科书上有两种归一化方式:一种叫幅值不变,一种叫功率不变。上面那个公式是幅值不变的——变换之后Iα的幅值等于原来Ia的幅值。另一种功率不变的系数是√(2/3)≈0.816,矩阵前面乘的是√(2/3)而不是2/3。这两种方式差了个√(3/2)≈1.22倍。
你在dq轴上调PI参数的时候,如果前向通道用了幅值不变,后向SVPWM输出的时候又按功率不变去算,整个电流环增益就差了22%。这个偏差在低速小扭矩下不明显,一到高速或者大扭矩工况,电流环响应慢半拍,振荡就来了,你还查不出来为什么——因为仿真里好好的。
我建议你在汽车电控项目里,从头到尾统一用幅值不变。道理很简单:你在台架上用示波器测到的相电流是多少安培,你在Iα、Iq通道里看到的就应该是多少安培,别让系数在中间偷偷转换。这样你调参的时候,物理量和代码量是对得上的,出了问题一眼就能看出来。
第二种,电流采样本身就不对。很多方案用两颗采样电阻,放在下桥臂,测B相和C相的电流。那A相电流怎么来?靠Ia = -Ib - Ic算出来。这个在大部分时候没问题,但在PWM占空比很小的时候——比如电机刚启动、或者低速大扭矩的时候——下桥臂导通时间太短,ADC采到的电流还没稳定就被打断了。这时候你算出来的Ia是噪声,Clarke变换之后Iα、Iβ全是毛刺,电流环就跟着抖。
汽车上现在比较成熟的做法是三电阻采样,或者用相电流传感器。但如果你成本受限必须用两电阻,软件上就得做文章:什么时候采样最准?答案是PWM计数器归零或者达到峰值的时刻——这时候三相下桥臂(或者上桥臂)同时导通,你测到的就是真实的相电流。而且采样时刻必须和PWM中断对齐,不能在中断服务函数里随便找个时间就采。
第三种,也是最隐蔽的——你以为你测的是Ia,其实测的是-Ia。这取决于采样电阻放在上桥臂还是下桥臂,以及ADC参考方向。硬件工程师画原理图的时候,电流从电阻上端流到下端,你采到的电压是正还是负,这个得在软件里做一次符号校准。
我见过一个项目,电机一上电流就飞车,查了两天发现B相采样方向反了,Clarke之后Iβ整个符号错掉,Id和Iq在做正弦振荡,电机当然就抖。
怎么验?很简单。把转子锁死,只给A相通一个正向直流电流,比如2A,B、C相不通。这时候Ia=2A,Ib=Ic=-1A。你看代码里算出来的Iα应该等于2A,Iβ应该等于0。如果Iβ不是0,要么采样方向反了,要么Clarke公式写错了。这个测试五分钟做完,能帮你排掉80%的低级错误。
03 Park变换:符号约定是你和硬件之间的合同
Park变换比Clarke更麻烦。因为它涉及角度θ,而θ这个东西,不同的人、不同的硬件、不同的编码器安装方向,符号约定都可能不一样。
标准写法,把αβ坐标系旋转θ角到dq坐标系:
Id = Iα·cosθ + Iβ·sinθ
Iq = -Iα·sinθ + Iβ·cosθ
然后逆Park变换(从dq回到αβ,给SVPWM用):
Vα = Vd·cosθ - Vq·sinθ
Vβ = Vd·sinθ + Vq·cosθ
你去翻TI、ST、Microchip的例程,会发现每家公式长得不太一样。有的Iq前面是正号,有的是负号。别觉得是人家写错了——这跟电机正方向怎么定义、编码器装在轴的哪一侧、d轴领先q轴还是落后q轴,全有关系。
这里的核心问题是:你正向Park的符号约定,必须和逆Park的符号约定,以及SVPWM输出的相序,三者严格一致。只要有一个地方符号反了,结果就是——你给Iq指令要正向扭矩,电机反而往后转;或者电机根本转不起来,一上电流就报过流。
我一般在代码里把坐标变换写成纯函数,不混在控制中断里。正向Park一个函数,逆Park一个函数,输入输出都很干净。你注意看:正向Park里Iq的表达式是 -Iα·sinθ + Iβ·cosθ,逆Park里Vα的表达式是 Vd·cosθ - Vq·sinθ。这两个符号是配套的。如果你哪天为了"让扭矩方向变正",把Iq那行改成 +Iα·sinθ - Iβ·cosθ,你必须同时把逆Park也翻过来,否则系统直接发散。
我强烈建议你在项目早期就把这套符号约定写成注释,钉在代码里。比如:theta定义为从A相轴线开始计量的转子电气角,正方向对应电机正转;q轴超前d轴90度电角度;正的Iq对应正方向扭矩。别嫌烦。三个月后你回来改代码,或者换个人接手,这行注释能救命。
04 角度θ从哪来:这才是真正的战场
说了半天Clarke和Park,真正决定你FOC性能的,是那个θ。
θ的来源大概就那么几种:霍尔传感器、光电编码器或者磁编码器、无位置传感器观测器。汽车上用得最多的是旋转变压器加解码芯片,或者磁编码器。不管哪种,你拿到手的都是一个位置值,你要做的事情有三件。
第一件,把机械角度换算成电气角度。极对数是P,那电气角θ = 机械角 × P。这个P你得跟电机厂确认,别自己猜,也别从 datasheet 上抄——很多电机厂家的极对数标得很随意,以实际标定为准。
第二件,找零位。编码器上电给你的是一个0到4095(举个例子)的机械位置,但哪个位置对应转子d轴跟A相绕组轴线重合?这个叫初始位置偏移,必须标定。怎么标?通一个直流电流,把转子d轴对齐到A相方向,这时候读编码器的值,存到Flash里。下次上电,编码器值减去这个偏移,才是你能用的θ。
这个偏移没标好会怎么样?我见过偏移差了90度电角度的,结果就是Id和Iq整个对调了。你给Iq=5A想要扭矩,实际电流全加在励磁上了,电机不转,电流却很大,直接堵转过流。还有一种偏移差了180度的,电机一上电就往反方向猛冲,那种事故在台架上见过好几次。
第三件,角度同步。这是最容易被忽略、却最影响性能的一点。
你的PWM频率可能是10kHz,也就是每100微秒一个中断。在这个中断里,你要做:采电流、Clarke、Park、PI、逆Park、SVPWM更新。这里面用的θ,是哪一时刻的转子角度?
如果你在上一个中断里读了一次θ,存起来,这个中断里用——那你用的是100微秒前的角度。在电机转速6000rpm、极对数4的情况下,100微秒转子转了多少电气度?我算给你听:6000转每分钟等于100转每秒,每转360度机械角,4对极就是14400度电气角每秒,100微秒就是1.44度电角度。看起来不大,但你别忘了,从你读θ到你真正更新PWM比较值,中间又经过了PI计算的时间,还有PWM更新到生效的延迟。累计下来,角度滞后可能到5到10度。
这个滞后会带来什么?Id和Iq之间出现交叉耦合。你想控Iq,结果一部分电流跑到Id上去了。低速下不明显,一到高速,电流环实际带宽掉得厉害,严重的时候整个电流环振荡。
怎么解决?工程上常用的办法是角度预测。你知道上次采样时刻的θ,知道上一次的角速度(从编码器速度环或者观测器微分得到),那这次采样时刻的θ就可以估算成 θ_now = θ_last + ω·ΔT。这个线性外推在大多数工况下够用了。要求更高的,还可以加个二阶预测,把角加速度也考虑进去。
但我得提醒你:角度预测不是万能药。如果你速度观测本身就有噪声,你把噪声放大到角度里,变换出来的Id、Iq就是抖的。所以角度预测一定要配合一个速度低通滤波,而且滤波带宽得跟你的电流环带宽匹配——不是越大越好,也不是越小越好。
05 落地时的几个工程细节
讲几个我在项目里反复踩过、也反复帮别人查过的点。
关于sin/cos怎么算。你在Cortex-M4或者C28x上,有DSP库可以调arm_sin_f32、arm_cos_f32,或者IQmath库里的IQsin、IQcos。这些函数内部用的是查表加插值,精度够,速度也够。但你要注意两件事:一是角度要wrap到0到2π范围内,不然查表越界;二是在10kHz中断里,每个中断要算两次sin/cos——正向Park一次,逆Park一次。你把算好的cosθ和sinθ存下来复用就行,别让CPU算两遍。
关于定点还是浮点。现在车规级MCU基本都带FPU了,你直接用float就行,别折腾Q格式。但如果你用的是老款的无FPU芯片,那定点变换的时候要特别注意中间量的溢出。比如Iβ=(Ia+2Ib)/√3,Ia和Ib可能到±20A,乘以2之后40A,再乘个系数,Q格式下一不小心就溢出。中间量一定要用高一级的精度去算,别图省事。
关于电流环带宽和坐标变换的关系。你的电流环带宽一般设在PWM频率的十分之一到二十分之一,也就是500Hz到1kHz左右。坐标变换本身不占带宽,但它引入的角度滞后会等效于在控制路径里加了一个纯延迟环节。这个延迟大概是1到1.5个PWM周期。如果你设计电流环的时候没把这个延迟算进去,调出来的PI参数在台架上能跑,一上整车,温度一高、母线电压一变,就开始振。
关于弱磁。电机基速以上要弱磁,你得给Id一个负的给定值。这时候角度精度更重要——因为Id本身就是负的小量,角度误差带来的Id/Iq交叉耦合,在弱磁区会被放大。很多人弱磁跑不好,去调弱磁PI调半天,其实根上还是角度同步没做好。
关于调试方法。我每次拿到一套新的FOC代码,做的第一件事不是转电机,而是先静态调试坐标变换:
把电机转子用机械方式锁死,不让它转。然后通过CAN或者调试接口,手动给θ从0度扫到360度,步长比如1度。同时记录Iα、Iβ、Id、Iq。
这时候你应该看到什么?转子锁死,相电流其实是固定的,因为没转,Iα和Iβ应该是两条固定值。但你手动旋转θ,Id和Iq应该变成:Id = Iα·cosθ + Iβ·sinθ,Iq = -Iα·sinθ + Iβ·cosθ。也就是说,Id和Iq应该是两条干净的正弦和余弦曲线,幅值等于√(Iα²+Iβ²),相位差90度。
如果你看到的不是干净的正弦——比如Id上面叠了毛刺、或者Id和Iq的相位差不对、或者幅值不对——那问题就锁死在Clarke/Park这一层了,跟PI、跟SVPWM都没关系。
这个静态测试,我建议你在每个新项目的第一天就做。花半小时,能省后面半个月的扯皮。
06 最后说几句实在话
FOC这个东西,入门容易,真正做扎实很难。网上一搜一大把教程,公式推得漂亮,仿真跑得也漂亮。但你真把代码烧到板子上,接个真电机,噪声、纹波、温度、电压波动、采样延迟全来了。
坐标变换这一层,看起来就几行代码,实际上它是连接"你脑子里的理想电机模型"和"板子上那堆硅片和铜绕组"的桥梁。桥没搭好,你后面PI调得再溜也是空中楼阁。
我见过太多工程师,一遇到问题就去翻PI参数,去翻SVPWM的占空比,唯独不肯花半小时把坐标变换这条链路从头到尾验一遍。原因也简单——公式太简单了,简单到让人觉得不值得花时间。
但恰恰是最简单的东西,最容易出最阴的bug。

#结构设计#研发#家电#清洁电器#园林工具#电动工具#机器人#无人机#电机#器械设备#电气#家居家具#吸尘器#洗地机#扫地机#高压清洗机#结构工程师#硬件开发#产品开发#整机设计#水泵#强老师讲技术















































































