Clarke-park 变换毫无意义

Posted on January 1, 2026

电机领域有个很神奇的现象:人云亦云,不会思考。

比如,早期有个教授写教材的时候说反电动势为梯形波的叫无刷,正弦波的叫永磁同步。 然后大家就跟着他这么说了,完全思考。

而国内做电机的,基本上教程来自德州仪器的电机库。几十年时间过去了,还没有跳出德州仪器当年给国内的人画的地牢。完全不会思考。 离了 Clarke-park 变换,就不会做 foc 了。 更有人写 foc 教程的时候,大言不惭的说,FOC离不开Clarke-park 变换,还说没有这个变换就没有 foc。

笑掉大牙,可是从业者都是这样的。不会思考,人云亦云。 长江大学的唐老师说的好,国内搞硬件的人,水平很差,喜欢对国外顶礼膜拜, 有问题都是自己的问题,但是如果国产的东西他自己水平次用出问题了,他又要怪国产芯片不行了,不找自己的问题了。 这种心态放到电机研究上,那就是永远不能跳出当年德州仪器规划出来的电机控制框架。 特别是,当德州仪器和 Matlab 合作搞出 simulink 电机控制开发套餐,国人就更不敢挑战了。 因为硬件领域是有一条鄙视链的,算法研究 》底层代码编写》搞应用落地的。 而 simulink 正好占据了电机算法研究领域的绝对统治地位。 搞研究的都用 simulink,他还处在鄙视链最上层,那么最下层的人就绝对不敢挑战权威,跳出 simulink 里的那套框架了。 特别是,中国搞电机研究的人,主要集中在高校里的 simulink算法党,和各大血汗工厂里的牛马应用党,最缺的是中间写底层代码的。因为这些活,被德州仪器等芯片工厂的“FAE”包了。 二十多年前,阿莫电子论坛上,有一个牛人在8051上手搓无刷电机驱动,被一些牛马党膜拜的同时,被另一批人嘲讽,有“原厂电机库” 好用吗? 他们的论据是,原厂电机库有很多不公开的高级算法,肯定是汇编写的,调用芯片底层资源的,你 C 写的肯定不行。 那么这个和 clarke -park 变换有什么关系呢? 因为德州仪器最早公开电机控制算法,“大公无私”的向下游公司提供电机控制库。还手把手的教他们怎么用。(大公无私打个引号,因为芯片是卖钱的。但是也算大公无私,因为他毕竟教了,而不是像日本公司那样只收钱,不教你)。 还做一系列的开发板,和 simulink 无缝集成。 无缝集成的意思是,在 simulink里动动鼠标,改改参数,就能让 simulink 自动生成一套基于 C2000 架构的电机控制代码。然后 simulink 自动调用德州仪器的编译器,下载到他的开发板上运行,一气呵成,只需要点 simulink 里的 “RUN”。。。。一行代码都不用写。 而这套体系,就是基于 Clarke -park 变换构建的。 可以说,这套 simulink 电机开发套件,就是国内一切电机开发的源头。 国内所有的论文,都是基于这套架构上做的开发。研究各种控制理论,也必须得先在这套架构上跑过才能发论文。

这个就是 唯“clarke-park变换”是尊的源头。

那么这个变换好不好呢?当然好,不好就不会被德州仪器选中。 但是,唯“clarke-park变换”是尊,正说明了国内的人不思进取,人云亦云。

因为,实际上,还有一个更好的。只不过,这套更好的方案,不太适合。。。 simulink 这套以“信号控制论”为基础设计的框架进行算法设计。只适合手搓 代码的情况下使用。

手搓 代码 可就要了高校那群算法党老鼻子命了。他们自然不用。

而处于鄙视链上层的人不用,下层的人自然就不敢用了。

那说了半天,我要搞个什么变换呢?

答案就是没有变换,只需要改下使用的坐标系。

Clarke-park 变换解决的问题,其实是直角坐标系下描述三相电麻烦的问题。 那我不使用直角坐标系不就完了?

其实,如果你去问电工,他如何描述三相电,你问他会不会给你进行 Clarke 变换。 答案就是不会。电工描述三相电,用的就是一个特殊的坐标系,“极坐标”。 电工对三相电的大小,用的是 “电压, 频率,相位” 三要素。而不是给你 Clarke-park 变换一下再用 Alpha Beta 坐标。 等等,交流电的瞬时电压时刻在变,怎么能用“电压”去描述呢? 在直角坐标系下,当然不能。

在直角坐标下,电压作为一个坐标,是会时刻变化的。这也是为何使用直角坐标系下,无法对交流电进行“直流控制”的原因。

但是,如果使用 极坐标,问题就迎刃而解。在极坐标里,描述一个三相电流矢量,用的是三相电的 (幅值,相位),对,哪怕是有3条电流,只需要2个维度的描述信息。 而且这个描述信息里的“幅值”是一个直流量。我们要对交流电机进行直流控制的时候,就只需要控制“幅值”这个直流量就可以了。 在极坐标系里,描述一个 foc 向量,用不到复杂的变换,就是简单粗暴的 幅值+角度。 幅值+角度作为一个整体描述的是三相电压的矢量,如何对应三相各自的电压,其实就是简单的 Ua = 幅值sin(角度), Ub = 幅值sin(角度+120),Uc = 幅值*sin(角度+240) 而“角度”这个东西,我们可以从编码器直接获取。 于是,foc的扭矩控制,就是简单的 PID 算法控制 幅值这个直流量。不涉及到任何变换和反变换操作。 也就是说,如果使用极坐标系,电机控制根本用不到 clarke 变换。因为没有这些变换,于是就没有了晦涩难懂的什么 D 坐标轴,Q坐标轴。 一切都是非常直观的,高中生都能理解的,交流电的本质定义,幅值和相位。 好了,一些在 DQ坐标系下很晦涩难懂的东西,在极坐标系你们会豁然开朗。

比如 D轴电流,Q轴电流,到底是什么意思。

其实,电工早就有了更通俗易懂的语言:无功,有功。

洋人最擅长的东西,就是语言上制造行业壁垒。pig meet 不能说,要说 pork。买涨不能说,要说买多。 无功,顾名思义,就是没有做工。为啥没有做工?因为电压和电流有相位差,用有效电压*有效电流算出来的功率会比实际功率大。这个比实际功率大的就叫“视在功率”。视在功率=无功+有功。有功占视在功率的比值呢,就是所谓的功率因素了。 然后功率因素正好,恰恰等于电压电流的相位差的 余玄值。于是一些教科书会定义功率因素=cos(电压电流相位差) 为啥会有相位差?因为电机的线圈有电感啊!

电感会导致电流滞后电压。于是就有了相位差。

foc控制,目的是控制磁场的矢量,而不是控制电压的矢量。必须得把这个相位差考虑进去。 因此,直接将转子位置的角度 + 90度,来生成定子的电压矢量,是不合适的。因为磁场是电流产生的,而不是电压。因此 foc控制,本质上是控制 “电流”的矢量角度,比转子磁场提前90度。要做到这点,电压实际上要提前更多。 至于提前多少? 在老式的有刷电机里,靠的是改变电刷的位置实现电压提前。但是这么做实际上很不精确。 因为电机的功率因素是会不断变化的,也就是说电压和电流的相位差并不固定。 因此,在foc控制里,需要精确的测量电压和电流的相位差,然后把这个相位差补偿进去。

在 clarke-park 变换里,这个补偿的算法,靠的是 把 IQ=0 做为控制目标。 为啥呢?因为 clarke-park 变换里,以转子的电角度为标准进行变换,如果电流矢量和转子的电角度差90度,则正好在它的视角里,无功=0。 如果把 IQ!=0 作为控制目标,就进入了所谓的“弱磁控制”。 本质上,就是让电流矢量比转子的电角度提前超过90度。这样因为磁场夹角超过90度,导致扭矩下降。。。。 但是,带来的另一个好处是反电动势下降。于是可以降低电机的 KV值,提高最高转速。缺点就是电压和电流的相位差进一步加大,也就是功率因素下降。功率因素下降,自然整套体系的效率也跟着下降。对续航是不利的,更好的做法是物理弱磁,也就是变KV电机=变磁通电机。 经过 clarke-park 变换后,很多人就失去了弱磁控制的本质理解了。因为变换来变换去,把你绕晕了。但是如果直接使用极坐标,不进行变换,你一眼就能看出来弱磁控制的本质。 所以,我反对 clarke-park 变换,就是因为这种变换遮掩了电机控制的本质,把简单问题复杂化。 包括 IQ=0 控制,也因为 clarke-park 变换 导致很多人云里雾里不知道为啥要这么干。只知道这么干扭矩最大。 但是在极坐标系下,你一眼就能看出来,这是为了对抗定子线圈电感的电流滞后效应。

另外在异步电机控制里,因为没有了“转子角度”这个东西,导致 park 变换输入的角度就回归回使用电压的相位角了。于是在异步电机控制里,clarke-park 变换后的 DQ坐标,本质上就是有功和无功。 但是,它们又要起一个新名词来糊弄你,叫 励磁电流,和做工电流。这是上坟烧报纸呢。 真正的励磁电流,是转子转差率导致转子切割磁感应线产生的电流。这个和 park变换后看到的 IQ 远的很呢。

那么,在抛弃了 clarke-park 变换后,到底要怎么进行foc控制呢?

首先,我们写这么一个底层函数, SetOutputVoltage(U, angle); 2个参数,一个是幅值,一个是角度。 SetOutputVoltage 最简单的做法是 Ua = 幅值sin(角度), Ub = 幅值sin(角度+120),Uc = 幅值*sin(角度+240)获得三相的输出电压,然后根据三相的输出电压计算占空比,配置到硬件 PWM 输出上。 当然,这种计算出来的波形叫 SPWM, 电压利用率不高。可以再进行一次三角波注入,计算出来的波形就叫 SVPWM 了(笑)。

接着,我们要写2个采样函数,一个叫 GetRotorAngle 一个叫 GetCurrent。GetRotorAngle 返回转子的角度(有传感器就直接读传感器,没传感器就用软件去估算,怎么估算就是另外的话题了)。GetCurrent返回三相电流的 “幅值和相位”。没错,不是直接返回三个相电流,而是返回计算后合成的 幅值和相位。 然后写一个控制环在 pwm中断里运行。这个控制环的计算很简单:

rotorAngle = GetRotorAngle(); // 获取转子角度 auto [current, currentAnagle] = GetCurrent(); // 获取电流幅值和相位 PID_caculated_U = toqueControl(current); // 根据电流计算电压 auto anglediff = last_VoltageAngle - currentAnagle ; // 计算电流电压的相位差 last_VoltageAngle = rotorAngle + 90 + anglediff; // 把相位差补进去 SetOutputVoltage(PID_caculated_U, last_VoltageAngle);

输出电压具体多少,在 toqueControl 里计算。要根据当前的电流值和目标进行反馈控制。内环是扭矩控制,是基础。如果是速度/位置模式,要再套一个外环。外环的输出是扭矩,再交给内环控制。

GetCurrent 如何返回电流的幅值和相位呢?因为硬件采集到的,实际上是独立的 ABC 三相的相电流,里面没有幅值信息,也没有相位信息。 实际上很简单,就是矢量合成。合成后的矢量,长度就是幅值,角度就是相位。 因此,可以套用矢量合成公式进行。也就是,输入的是 Ia Ib Ic 三相电流, 其长度是

$ \sqrt (2/3*(Ia^2 + Ib^2 + Ic^2)) $

而相位,则是 asin(Ia/幅值)

在极坐标体系下,会发现不需要 atan 运算。而这个运算在 clarke-park 体系下是必须的。为了避免 atan 在 90度下的无穷大问题,一般还要使用 atan2 这个函数。

Comments