2. Clark变换与Park变换:三相静止到两相旋转的坐标魔法

做电机控制这些年,我越来越觉得坐标变换就像变魔术。你想想看,三相电机里那些缠缠绕绕的电流,经过两次变换,居然能变成直流一样的量,直接控制转矩和磁通。这背后就是Clark和Park这对黄金搭档。

我个人习惯把Clark变换叫做「3→2」,Park变换叫做「2→2旋转」。别小看这两个变换,它们是FOC(磁场定向控制)的基石。今天我们就把它彻底讲透。

2.1 为什么非变不可?

三相电机有三相绕组,电流是交流的,互相差120度。直接控制这三相电流去调转矩?太复杂了。你想想,转矩和磁通是耦合在一起的,调一个另一个也跟着变。

Clark变换先把三相变成两相,相当于把电机从「三脚架」变成「十字架」。Park变换再把这个静止的十字架旋转起来,让它跟转子同步。这样一来,交流量就变成了直流量,控制起来跟调直流电机一样简单。

我在项目中遇到过一位同事,死活不理解为什么要做变换。他直接用PID调三相电流,结果电机嗡嗡响,转矩抖得厉害。后来我给他画了张图,他一看就明白了——坐标变换的本质就是「换个角度看问题」。

核心思想:把时变的交流量,变成时不变的直流量。控制难度直接降一个维度。

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

Clark变换也叫3s/2s变换。输入是三相电流ia、ib、ic,输出是两相电流iα、iβ。这两个轴互相垂直,α轴和A相轴线重合。

公式其实很简单:

iα = ia
iβ = (ia + 2*ib) / √3

等等,你是不是觉得少了点什么?ic去哪了?

嗯,这里有个小秘密:三相电流满足ia + ib + ic = 0。所以ic = -ia - ib,根本不需要单独测量。我在做第一版代码时就踩过这个坑——多采了一路电流,白白浪费了一个ADC通道。

完整的矩阵形式是这样的:

[iα]   [ 1      -1/2     -1/2  ] [ia]
[iβ] = [ 0      √3/2    -√3/2 ] [ib]
                                [ic]

实际代码里,我们一般用等幅值变换,系数是2/3:

// Clark变换代码实现
void clark_transform(float ia, float ib, float ic, float *i_alpha, float *i_beta) {
    // 等幅值变换,系数2/3
    *i_alpha = (2.0f/3.0f) * (ia - 0.5f*ib - 0.5f*ic);
    *i_beta  = (2.0f/3.0f) * (0.866025f*ib - 0.866025f*ic);
    
    // 如果三相平衡,可以简化
    // *i_alpha = ia;
    // *i_beta  = (ia + 2.0f*ib) / 1.73205f;
}

避坑指南:我曾经在定点DSP上做Clark变换,忘了处理浮点数精度问题。结果电机低速运行时,iβ分量有0.5%的误差,导致转矩脉动。后来改用Q15格式,问题就解决了。

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

Clark变换之后,我们有了iα和iβ。但它们还是交流量——转子转一圈,它们也跟着变一次。Park变换就是要把这个静止坐标系「转起来」。

旋转的关键是转子位置角θ。你想想看,如果我们跟着转子一起转,看到的电流就是恒定的了。

公式:

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

这里id是直轴电流(产生磁通),iq是交轴电流(产生转矩)。FOC的核心就是:控制id恒定,控制iq调转矩。

// Park变换代码实现
void park_transform(float i_alpha, float i_beta, float theta, 
                    float *i_d, float *i_q) {
    float sin_theta = sinf(theta);
    float cos_theta = cosf(theta);
    
    *i_d =  i_alpha * cos_theta + i_beta * sin_theta;
    *i_q = -i_alpha * sin_theta + i_beta * cos_theta;
}

注意:θ必须是电角度,不是机械角度。对于一对极电机,电角度=机械角度。对于多对极电机,电角度=机械角度×极对数。我见过有人直接用编码器读数做Park变换,结果电机完全失控——因为忘了乘极对数。

2.4 逆变换:从旋转回到静止

控制完id和iq,我们还得把它们变回三相电压,才能给逆变器发PWM。这就是逆Park和逆Clark。

逆Park变换:

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

逆Clark变换:

va = vα
vb = -0.5*vα + 0.866025*vβ
vc = -0.5*vα - 0.866025*vβ
// 逆Park变换
void inv_park_transform(float i_d, float i_q, float theta,
                        float *i_alpha, float *i_beta) {
    float sin_theta = sinf(theta);
    float cos_theta = cosf(theta);
    
    *i_alpha = i_d * cos_theta - i_q * sin_theta;
    *i_beta  = i_d * sin_theta + i_q * cos_theta;
}

// 逆Clark变换
void inv_clark_transform(float v_alpha, float v_beta,
                         float *v_a, float *v_b, float *v_c) {
    *v_a = v_alpha;
    *v_b = -0.5f * v_alpha + 0.866025f * v_beta;
    *v_c = -0.5f * v_alpha - 0.866025f * v_beta;
}

2.5 知识体系总览

下面这张图,是我做培训时必画的。它把整个变换链路串起来了:

坐标变换知识体系 三相静止坐标系 ia, ib, ic Clark 两相静止坐标系 iα, iβ Park 两相旋转坐标系 id, iq 逆Park 逆Clark FOC控制流程 采样ia, ib, ic Clark变换 Park变换 PI调节 逆变换 → SVPWM → 逆变器 → 电机

2.6 工程实现要点

代码写起来不难,但工程实现有几个坑要避开:

  • 角度同步:Park变换用的θ必须和采样时刻对齐。我建议在PWM中断里统一采样、变换、计算,一气呵成。
  • 三角函数计算:别用标准库的sin/cos,太慢了。用查表法或者CORDIC算法。我在STM32上做过测试,查表法比标准库快5倍。
  • 定点化:如果MCU没有FPU,一定要做定点化。Q15格式是业界标准,精度够用。
  • 溢出保护:变换过程中可能出现数值溢出,尤其是逆Clark变换输出三相电压时。记得做限幅。

我的习惯:调试时先把Clark和Park变换单独拿出来测试。给一组已知的三相电流,看变换后的id、iq对不对。这一步没问题了,再联调整个FOC环路。否则出了问题,你根本不知道是变换错了还是PI参数没调好。

好了,Clark和Park变换就讲到这里。说白了就是两次坐标旋转,把交流变直流。代码我给你了,图也画了,剩下的就是动手去试。记住,纸上得来终觉浅,绝知此事要躬行。

专注资料整理