3. 坐标变换基础:Clark变换与Park变换的数学推导、物理意义与仿真验证

说到FOC,绕不开的第一个坎就是坐标变换。很多初学者一上来就被αβ、dq搞晕了。我当年也一样,看了三天公式,脑子里还是一团浆糊。后来我发现,问题出在没搞懂一件事——变换到底是为了什么。

说白了,我们做坐标变换,就是为了把交流电机里那些随时间变化的量,变成直流电机里那种好控制的直流量。你想想看,PID控制器最喜欢处理什么?恒定值。如果直接拿三相正弦电流去调,那得调出花来。所以,先变换,再控制。

3.1 为什么需要坐标变换?

三相永磁同步电机(PMSM)的数学模型,在自然坐标系(ABC)下是时变的。电感、磁链都跟着转子位置转。你写出来的微分方程,系数全是时间的函数。这怎么解?

我刚开始做项目时,直接拿三相模型去搭仿真,结果跑一步要算半天,还经常发散。后来老工程师跟我说:“你先把它变到旋转坐标系下,再试试。” 果然,一下就稳了。

所以,坐标变换的核心目的就两个:

  • 解耦:把强耦合的三相系统,变成两个独立的直流系统(d轴和q轴)。
  • 简化控制:让PI控制器能直接对直流量进行无静差调节。

核心思想:Clark变换把三相变两相(静止),Park变换把静止变旋转。两步走完,交流变直流。

3.2 Clark变换:从ABC到αβ

Clark变换,也叫3s/2s变换。就是把三相静止坐标系(A、B、C),投影到两相静止坐标系(α、β)上。

数学上很简单,就是投影。假设三相电流幅值相等,相位互差120°。我们取α轴与A轴重合,β轴超前α轴90°。那么:

Iα = Ia
Iβ = (Ia + 2*Ib) / √3

等等,这公式看着有点眼熟?其实它就是三相电流在αβ轴上的投影和。完整的矩阵形式是这样的:

[ Iα ]   [ 1,  -1/2,  -1/2 ] [ Ia ]
[    ] = [                     ] [    ]
[ Iβ ]   [ 0,  √3/2, -√3/2 ] [ Ib ]
                              [ Ic ]

注意,这里用的是等幅值变换。还有一种叫等功率变换,系数会差一个√(2/3)。我个人习惯用等幅值,因为调试时电流环的PI参数好算,直接对应物理电流值。

我的经验:在代码实现时,Clark变换只需要采样两相电流(Ia、Ib),Ic = -Ia - Ib。省一个ADC通道,还能省点成本。我在一个量产项目上就这么干的,跑了三年没出过问题。

3.3 Park变换:从αβ到dq

Clark变换做完,我们得到了两个正交的正弦波(Iα、Iβ)。它们还是交流量,幅值不变,频率不变。接下来,Park变换登场。

Park变换,也叫2s/2r变换。就是把静止的αβ坐标系,旋转到与转子磁极同步的dq坐标系上。d轴对准转子磁极方向,q轴超前d轴90°。

变换公式:

Id =  Iα * cos(θ) + Iβ * sin(θ)
Iq = -Iα * sin(θ) + Iβ * cos(θ)

这里的θ,就是转子电角度。从编码器或霍尔传感器读到的位置,乘以极对数,就是θ。

做完这一步,Id和Iq就变成了直流量。Id控制励磁,Iq控制转矩。两个独立的直流回路,各调各的,互不干扰。

避坑指南:我曾经在一个项目上,因为编码器安装时零位偏了5度,结果电机空载电流大了30%。后来排查了三天,才发现是Park变换的θ初始值没对准。所以,上电后的转子初始位置对齐,是FOC调试的第一步,千万别省。

3.4 逆变换:从dq回到ABC

控制环路算完,我们得到的是Vd和Vq(电压指令)。但最终要给电机的是三相电压(Va、Vb、Vc)。所以,还得变回去。

先做逆Park变换(dq → αβ):

Vα = Vd * cos(θ) - Vq * sin(θ)
Vβ = Vd * sin(θ) + Vq * cos(θ)

再做逆Clark变换(αβ → ABC):

Va = Vα
Vb = -0.5 * Vα + (√3/2) * Vβ
Vc = -0.5 * Vα - (√3/2) * Vβ

最后,把Va、Vb、Vc送给SVPWM模块,生成驱动信号。整个FOC的电流环,就是靠这一正一反两次变换,把交流问题变成了直流问题。

3.5 物理意义:到底在变什么?

公式推完了,我们来聊聊物理意义。我见过不少工程师,代码写得飞起,但问他Id和Iq到底代表什么,说不清楚。

  • Id(直轴电流):产生磁场的电流。在PMSM里,转子本身有永磁体,所以Id通常控制为0(表贴式电机),或者负值(内置式电机,用于弱磁)。
  • Iq(交轴电流):产生转矩的电流。你踩油门,实际上就是在调Iq。
  • Clark变换:把三相绕组的合力,分解到两个正交的轴上。相当于把三个力,合成两个力。
  • Park变换:把这两个力,旋转到与转子同步的坐标系里。这样,不管转子转到哪,你看到的Id和Iq都是恒定的。

说白了,Clark变换是降维,Park变换是同步。两个合起来,就是把一个时变、耦合的系统,变成一个时不变、解耦的系统。

3.6 仿真验证:用数据说话

光说不练假把式。我们搭个简单的仿真,看看变换前后的波形。

假设三相电流:

Ia = 10 * sin(ωt)
Ib = 10 * sin(ωt - 120°)
Ic = 10 * sin(ωt + 120°)

经过Clark变换后,Iα和Iβ的波形:

  • Iα = 10 * sin(ωt)
  • Iβ = 10 * cos(ωt)

幅值不变,相位差90°。还是正弦波。

再经过Park变换(假设θ = ωt,转子同步旋转):

  • Id = 10 * sin(ωt) * cos(ωt) + 10 * cos(ωt) * sin(ωt) = 10 * sin(2ωt) / 2 + 10 * sin(2ωt) / 2 = 10 * sin(2ωt) ???

等等,这里有问题。如果Id和Iq还是正弦波,那变换就没意义了。实际上,正确的Park变换公式里,Id和Iq应该是常数。我们来算一下:

Id = Iα * cos(θ) + Iβ * sin(θ)
   = 10*sin(ωt)*cos(ωt) + 10*cos(ωt)*sin(ωt)
   = 10 * sin(2ωt)   // 这不对!

问题出在哪?出在Iβ的符号。正确的Iβ应该是 -10*cos(ωt) 吗?不,我们重新推导一下。

三相电流:

Ia = 10 * sin(ωt)
Ib = 10 * sin(ωt - 120°) = 10 * [sin(ωt)*cos(120°) - cos(ωt)*sin(120°)]
   = 10 * [-0.5*sin(ωt) - (√3/2)*cos(ωt)]
Ic = 10 * sin(ωt + 120°) = 10 * [sin(ωt)*cos(120°) + cos(ωt)*sin(120°)]
   = 10 * [-0.5*sin(ωt) + (√3/2)*cos(ωt)]

Clark变换(等幅值):

Iα = Ia = 10 * sin(ωt)
Iβ = (Ia + 2*Ib) / √3
   = [10*sin(ωt) + 2*10*(-0.5*sin(ωt) - (√3/2)*cos(ωt))] / √3
   = [10*sin(ωt) - 10*sin(ωt) - 10*√3*cos(ωt)] / √3
   = -10 * cos(ωt)

所以,正确的Iβ = -10 * cos(ωt)。

然后做Park变换(θ = ωt):

Id = Iα * cos(θ) + Iβ * sin(θ)
   = 10*sin(ωt)*cos(ωt) + (-10*cos(ωt))*sin(ωt)
   = 10*sin(ωt)*cos(ωt) - 10*cos(ωt)*sin(ωt)
   = 0

Iq = -Iα * sin(θ) + Iβ * cos(θ)
   = -10*sin(ωt)*sin(ωt) + (-10*cos(ωt))*cos(ωt)
   = -10*sin²(ωt) - 10*cos²(ωt)
   = -10 * (sin²(ωt) + cos²(ωt))
   = -10

看,Id = 0,Iq = -10(负号表示电流方向与定义相反,取绝对值即可)。两个直流量,完美。

仿真结论:只要Park变换的角度θ与转子同步,Id和Iq就是常数。这就是FOC能实现精准控制的理论基础。

3.7 知识体系图

下面这张图,把整个坐标变换的流程和关系画清楚了。我建议你把它存下来,每次写代码前看一眼。

FOC坐标变换知识体系图 FOC坐标变换知识体系 自然坐标系 (ABC) 三相静止,时变耦合 Clark变换 静止两相 (αβ) 两相静止,仍为正弦 Park变换 旋转两相 (dq) 两相旋转,直流恒定 逆Park 逆Clark 物理意义 • Clark变换:降维(3→2),把三相绕组合力投影到两个正交轴上 • Park变换:同步(静止→旋转),把静止两相旋转到与转子同步的坐标系 • 最终效果:时变→恒定,耦合→解耦,交流→直流 关键参数与变换关系 变换类型 输入 输出 关键参数 Clark (3s/2s) Ia, Ib, Ic Iα, Iβ 无(固定变换矩阵) Park (2s/2r) Iα, Iβ, θ Id, Iq 转子电角度 θ

3.8 代码实现要点

最后,聊几句代码实现。我见过很多新手把变换公式写得很长,其实可以很简洁。

// Clark变换(等幅值)
void clark_transform(float Ia, float Ib, float *Ialpha, float *Ibeta) {
    *Ialpha = Ia;
    *Ibeta  = (Ia + 2.0f * Ib) * 0.57735f;  // 1/√3 ≈ 0.57735
}

// Park变换
void park_transform(float Ialpha, float Ibeta, float theta, float *Id, float *Iq) {
    float sin_theta = sinf(theta);
    float cos_theta = cosf(theta);
    *Id =  Ialpha * cos_theta + Ibeta * sin_theta;
    *Iq = -Ialpha * sin_theta + Ibeta * cos_theta;
}

// 逆Park变换
void inv_park_transform(float Vd, float Vq, float theta, float *Valpha, float *Vbeta) {
    float sin_theta = sinf(theta);
    float cos_theta = cosf(theta);
    *Valpha = Vd * cos_theta - Vq * sin_theta;
    *Vbeta  = Vd * sin_theta + Vq * cos_theta;
}

// 逆Clark变换
void inv_clark_transform(float Valpha, float Vbeta, float *Va, float *Vb, float *Vc) {
    *Va = Valpha;
    *Vb = -0.5f * Valpha + 0.86603f * Vbeta;  // √3/2 ≈ 0.86603
    *Vc = -0.5f * Valpha - 0.86603f * Vbeta;
}

性能提示:在嵌入式MCU上,sin/cos计算很费时间。我一般用查表法或者CORDIC算法。如果芯片有FPU和硬件三角函数(比如STM32G4系列),直接调库函数也行。但要注意,角度θ的单位是弧度,别传错了。

嗯,坐标变换这部分,说难不难,说简单也不简单。关键是要理解为什么变和变了之后怎么用。公式记不住没关系,写代码时查一下就行。但物理意义一定要吃透,不然后面调电流环、速度环,你会一头雾水。