4. Clark变换与Park变换:从三相到两相,从静止到旋转

好,咱们进入坐标变换这一章。说实话,很多做电机控制的同行,一开始都被这三个字母绕晕——ABC、αβ、dq。其实没那么玄乎。你想想看,电机里转的是磁场,我们测的是三相电流,但控制目标是要让电流跟转子位置对齐。那怎么对齐?就得靠这两步变换。

我个人习惯把Clark变换和Park变换看作两把尺子。第一把尺子把三相静止坐标系(ABC)变成两相静止坐标系(αβ),第二把尺子再把两相静止坐标系(αβ)变成两相旋转坐标系(dq)。做完这两步,交流量就变成了直流量,PID才能上去干活。

4.1 为什么非变不可?

先问个问题:三相电流是正弦波,你用PID去跟踪正弦波,能跟踪好吗?能,但带宽要求极高,而且稳态误差很难消除。我早期做项目时试过直接在三相上做PI,结果电流波形抖得跟心电图似的。

后来才明白,核心思路是——把交流变直流。怎么变?让坐标系跟着转子一起转。这样,原本旋转的电流矢量,在新的坐标系里就静止了。静止的东西,PID闭着眼睛都能控好。

核心思想: 三相交流 → 两相交流(Clark) → 两相直流(Park) → 用PI控直流 → 反变换回三相 → 驱动电机。

4.2 Clark变换:三相静止 → 两相静止

Clark变换,也叫3s/2s变换。它的任务是把三相绕组上的电流,投影到两个正交的轴上去。这两个轴我习惯叫α轴和β轴,α轴跟A相轴线重合,β轴超前α轴90度。

数学上很简单,就是矩阵乘法:

// Clark变换(等幅值变换)
i_alpha = i_a
i_beta  = (i_a + 2*i_b) / sqrt(3)

注意,这里我用了等幅值变换。还有一种叫等功率变换,系数不同。我个人习惯用等幅值,因为调试时看电流波形更直观——三相电流幅值10A,变换后αβ幅值也是10A,心里有数。

我的习惯: 项目里统一用等幅值变换。等功率变换虽然功率守恒,但幅值会变,调试时容易算错PI参数。你选一种,从头到尾保持一致就行。

Clark变换的物理意义是什么?说白了,就是把三个绕组产生的磁动势,等效成两个正交绕组产生的磁动势。三相绕组在空间上差120度,两相绕组在空间上差90度。只要匝数合适,产生的旋转磁场一模一样。

4.3 Park变换:两相静止 → 两相旋转

Clark变换做完,我们有了αβ坐标系下的电流。但这两个量还是正弦波,因为坐标系没动。接下来Park变换上场——把αβ坐标系旋转起来,让它跟着转子走。

旋转的角度就是转子位置角θ,一般由编码器或霍尔传感器提供。Park变换的公式:

// Park变换
i_d =  i_alpha * cos(θ) + i_beta * sin(θ)
i_q = -i_alpha * sin(θ) + i_beta * cos(θ)

做完这一步,i_d和i_q就变成了直流量。i_d对应励磁分量,i_q对应转矩分量。你想想看,控制电机转矩,直接调i_q就行;控制弱磁,调i_d就行。多清爽。

我曾经踩过的坑: 角度θ的零点对齐问题。如果编码器零位跟电机A相反电动势零点没对齐,Park变换出来的d轴电流会包含转矩分量,导致你调i_d时电机乱转。所以上电第一件事,先做角度对齐校准。

4.4 变换的物理意义:到底在干什么?

我换个角度给你讲。你站在电机外面看,三相电流在空间里转,你看到的是三个正弦波。但如果你坐在转子上看呢?你跟着转子一起转,那三个绕组在你眼里就是静止的。电流在你眼里就是恒定值。

Clark变换是第一步:把三个绕组的视角,简化成两个正交绕组的视角。Park变换是第二步:你跳上转子,跟着它一起转。两步做完,你看到的电流就是直流量了。

反过来,你要输出控制电压,就得做逆变换:

  • 反Park变换: dq → αβ
  • 反Clark变换: αβ → ABC

这两步就是SVPWM的输入。整个流程串起来,就是FOC(磁场定向控制)的核心骨架。

4.5 代码实现:C语言版

下面是我在项目中常用的实现。注意,我用了浮点运算,如果你用定点DSP,记得做Q格式转换。

typedef struct {
    float i_alpha;
    float i_beta;
} Clarke_Output;

typedef struct {
    float i_d;
    float i_q;
} Park_Output;

// Clark变换
Clarke_Output clark_transform(float i_a, float i_b, float i_c) {
    Clarke_Output out;
    out.i_alpha = i_a;
    out.i_beta  = (i_a + 2.0f * i_b) / 1.7320508f;  // sqrt(3)
    return out;
}

// Park变换
Park_Output park_transform(float i_alpha, float i_beta, float theta) {
    Park_Output out;
    float sin_t = sinf(theta);
    float cos_t = cosf(theta);
    out.i_d =  i_alpha * cos_t + i_beta * sin_t;
    out.i_q = -i_alpha * sin_t + i_beta * cos_t;
    return out;
}

// 反Park变换
void inv_park_transform(float i_d, float i_q, float theta,
                        float *i_alpha_ref, float *i_beta_ref) {
    float sin_t = sinf(theta);
    float cos_t = cosf(theta);
    *i_alpha_ref = i_d * cos_t - i_q * sin_t;
    *i_beta_ref  = i_d * sin_t + i_q * cos_t;
}

性能提示: sin/cos计算很费时间。我一般用查表法或者Cordic算法。如果MCU有硬件三角函数单元,记得使能。别让变换吃掉你一半的CPU时间。

4.6 变换流程总图

下面这张图把整个变换链路画清楚了。从三相电流采样开始,到SVPWM输出结束,中间就是Clark→Park→PI→反Park→反Clark。你调试电流环时,脑子里要时刻有这个图。

FOC坐标变换链路 三相电流采样 Clark变换 Park变换 PI控制器 反Park变换 反Clark变换 SVPWM 逆变器输出 转子位置 θ Clark变换:ABC → αβ(三相静止 → 两相静止) Park变换:αβ → dq(两相静止 → 两相旋转,跟随转子)

4.7 常见问题与避坑

最后,我总结几个实际项目中容易出问题的地方:

问题 现象 原因 解决办法
角度零点偏移 i_d和i_q有交流分量 编码器零位未对齐 做角度校准,或软件补偿
变换系数不一致 电流幅值不对,PI参数失效 等幅值与等功率混用 统一用一种,推荐等幅值
sin/cos计算延迟 高速时电流畸变 角度更新不够快 用查表法或硬件加速
三相采样顺序错 Clark输出异常 ADC采样时序没对齐 确保三相同时采样或补偿

我曾经遇到一个特别隐蔽的问题: 某次调试,电机低速时电流波形正常,一上高速就开始抖。查了两天,发现是Park变换里用的角度是上一拍的,延迟了一个PWM周期。高速时角度变化快,一拍延迟就导致dq轴耦合。后来改成预测角度,问题解决。所以,角度更新的实时性,比你想象的重要得多。