坐标变换理论:Clark变换、Park变换与反变换

坐标变换,说白了就是换个角度看问题。

你想想看,电机里三相绕组通的是交流电,产生的磁场在空间里转。可我们做控制,最习惯的是处理直流信号——给多大电流,出多大转矩,简单直接。那能不能把交流电机控制得像直流电机一样爽?

能。靠的就是坐标变换。

这套理论不是我发明的,但我在项目里用了不下几十次。每次调试新板子,第一步就是验证坐标变换算得对不对。这一步错了,后面全是白搭。

为什么需要坐标变换?

三相电机有三相绕组,A、B、C。它们空间上差120°,电流时间上也差120°。你盯着三相电流看,三个正弦波,相位不同,幅值相同。想靠这三个量直接做转矩控制?麻烦。

但如果我们换个坐标系:

  • αβ坐标系:把三相投影到两相正交轴上,静止不动。
  • dq坐标系:让坐标系跟着转子转,这样交流量就变成了直流量。

这样一来,控制就变成了:调d轴电流(励磁分量),调q轴电流(转矩分量)。跟直流电机一模一样。

核心思想:坐标变换不改变物理本质,只改变数学描述。电机还是那个电机,但控制难度降了一个数量级。

Clark变换(3s/2s)

Clark变换,就是把三相静止坐标系(A、B、C)变换到两相静止坐标系(α、β)。

公式很简单:

iα = iA
iβ = (iA + 2*iB) / √3

等等,这里有个细节。上面这个是等幅值变换,我项目里最常用的。还有一种叫等功率变换,系数不一样。

变换类型 α轴系数 β轴系数 适用场景
等幅值变换 1 1/√3 电流环控制(我最常用)
等功率变换 √(2/3) √(2/3) 功率计算、效率分析

我的习惯:做电流环控制时用等幅值变换,因为电流限幅直观。做系统仿真或效率标定时用等功率变换。别混用,否则算出来的功率对不上。

Clark变换的物理意义是什么?就是把三相绕组的合成磁动势,等效成两相正交绕组产生的磁动势。说白了,三个线圈干的事,两个线圈也能干,只要电流算对了。

Park变换(2s/2r)

Clark变换完了,我们有了αβ坐标系下的电流。但αβ还是静止的,电流仍然是交流量。要把它变成直流量,就得让坐标系转起来。

Park变换,就是把两相静止坐标系(α、β)变换到两相旋转坐标系(d、q)。

公式:

id = iα * cosθ + iβ * sinθ
iq = -iα * sinθ + iβ * cosθ

这里的θ,就是转子位置角。一般来自编码器或霍尔传感器。

我在项目里踩过一个坑:角度对齐问题。编码器安装时有个零位偏移,如果这个偏移没校准,Park变换出来的dq电流就是错的。电机能转,但效率低、噪音大、还容易抖。

注意:Park变换依赖准确的角度信息。角度误差1°,转矩控制精度就下降约1.7%。角度误差超过30°,电机基本没法正常控制。

Park变换之后,id和iq就是直流量了。id控制励磁,iq控制转矩。你给一个阶跃指令,电流环就能稳稳地跟上去。这就是矢量控制的精髓。

反Park变换与反Clark变换

控制算法算出来的是dq坐标系下的电压指令。但最终要加到电机上的,是三相电压。所以得把dq变回去。

反Park变换(2r/2s):

uα = ud * cosθ - uq * sinθ
uβ = ud * sinθ + uq * cosθ

反Clark变换(2s/3s):

uA = uα
uB = -0.5 * uα + (√3/2) * uβ
uC = -0.5 * uα - (√3/2) * uβ

你看,反变换就是正变换的逆过程。数学上是对称的,实现起来也简单。

但有个细节:反Clark变换出来的三相电压,是相对于中性点的相电压。如果你用的是三相全桥驱动,还需要转换成线电压或者直接给SVPWM模块用。这个后面章节会细讲。

完整变换流程

整个坐标变换的链路是这样的:

坐标变换完整流程 三相电流 iA, iB, iC Clark变换 3s → 2s Park变换 2s → 2r 电流环控制 id, iq 调节 反Park变换 2r → 2s 反Clark变换 2s → 3s SVPWM调制 生成驱动信号 三相逆变器 驱动电机 采样 → Clark → Park → 控制 → 反Park → 反Clark → SVPWM → 驱动 每个周期执行一次,通常在PWM中断里完成

这个流程,每个PWM周期跑一次。我一般放在ADC采样完成中断里,先读电流,然后做变换,再跑控制算法,最后反变换输出。整个链路要在几十微秒内完成。

代码实现要点

实际写代码时,我建议把坐标变换封装成独立的函数。这样调试方便,也容易移植。

// Clark变换(等幅值)
void clark_transform(float iA, float iB, float iC, float *iAlpha, float *iBeta) {
    *iAlpha = iA;
    *iBeta  = (iA + 2.0f * iB) * 0.577350269f;  // 1/√3
}

// Park变换
void park_transform(float iAlpha, float iBeta, float theta, float *id, float *iq) {
    float cos_t = cosf(theta);
    float sin_t = sinf(theta);
    *id = iAlpha * cos_t + iBeta * sin_t;
    *iq = -iAlpha * sin_t + iBeta * cos_t;
}

// 反Park变换
void inv_park_transform(float ud, float uq, float theta, float *uAlpha, float *uBeta) {
    float cos_t = cosf(theta);
    float sin_t = sinf(theta);
    *uAlpha = ud * cos_t - uq * sin_t;
    *uBeta  = ud * sin_t + uq * cos_t;
}

// 反Clark变换
void inv_clark_transform(float uAlpha, float uBeta, float *uA, float *uB, float *uC) {
    *uA = uAlpha;
    *uB = -0.5f * uAlpha + 0.866025404f * uBeta;   // √3/2
    *uC = -0.5f * uAlpha - 0.866025404f * uBeta;
}

性能优化建议:三角函数用查表法或者CORDIC算法,别直接调math.h里的cosf/sinf,太慢了。我一般用512点或1024点的正弦表,精度够用,速度能快5倍以上。

常见问题与避坑

  • 电流采样顺序:三相电流要同时采样,或者至少在一个PWM周期内完成。我用的是双采样模式,在PWM载波顶点和底点各采一次。
  • 角度补偿:从采样到变换完成有延迟,角度需要做补偿。我一般根据当前转速估算角度增量,加到采样时刻的角度上。
  • 数值精度:定点MCU上做变换,注意溢出。我习惯先把电流缩放到Q12或Q15格式,算完再缩放回来。

我曾经踩过的坑:有一次调试,电机低速时正常,高速时电流波形畸变。查了两天,发现是角度更新频率不够。PWM频率20kHz,但角度计算只做了1kHz。高速时角度跟不上,Park变换出来的dq电流全是纹波。后来把角度计算也放到PWM中断里,问题解决。

坐标变换,说难不难,说简单也不简单。关键是要理解它的物理意义,而不仅仅是背公式。你想想看,三个线圈转成一个线圈,再转成两个直流分量——这套思想,贯穿了整个电机控制领域。

嗯,这一章就到这里。把变换吃透了,后面的SVPWM、电流环、速度环,都会顺很多。