2. Clark变换与Park变换实现

任务目标

本案例实现永磁同步电机FOC控制中的核心坐标变换:Clark变换(三相静止abc坐标系 → 两相静止αβ坐标系)与Park变换(两相静止αβ坐标系 → 两相旋转dq坐标系),并验证变换数学正确性。输入为三相电流 \( i_a, i_b, i_c \) 与转子电角度 \( \theta_e \),输出为 \( i_d, i_q \)。

核心公式与实现

采用等幅值变换(系数2/3),Clark变换公式为:

\[ i_\alpha = \frac{2}{3}(i_a - \frac{1}{2}i_b - \frac{1}{2}i_c), \quad i_\beta = \frac{2}{3}(\frac{\sqrt{3}}{2}i_b - \frac{\sqrt{3}}{2}i_c) \]

Park变换公式为:

\[ i_d = i_\alpha\cos\theta_e + i_\beta\sin\theta_e, \quad i_q = -i_\alpha\sin\theta_e + i_\beta\cos\theta_e \]

代码中直接使用 sinf/cosf 计算三角函数,无外部依赖,仅需标准C库。

关键完整代码

#include <stdio.h>
#include <math.h>

#define PI 3.14159265358979323846

typedef struct {
    float alpha;
    float beta;
} AlphaBeta;

typedef struct {
    float d;
    float q;
} DQ;

// Clark变换:三相abc → 两相静止αβ(等幅值)
AlphaBeta clark_transform(float ia, float ib, float ic) {
    AlphaBeta ab;
    ab.alpha = (2.0f/3.0f) * (ia - 0.5f*ib - 0.5f*ic);
    ab.beta  = (2.0f/3.0f) * (0.8660254f*ib - 0.8660254f*ic); // sqrt(3)/2
    return ab;
}

// Park变换:αβ → dq(转子磁场定向)
DQ park_transform(float alpha, float beta, float theta_elec) {
    DQ dq;
    float cos_t = cosf(theta_elec);
    float sin_t = sinf(theta_elec);
    dq.d =  alpha * cos_t + beta * sin_t;
    dq.q = -alpha * sin_t + beta * cos_t;
    return dq;
}

// 组合变换:abc → dq(一步到位)
DQ abc_to_dq(float ia, float ib, float ic, float theta_elec) {
    AlphaBeta ab = clark_transform(ia, ib, ic);
    return park_transform(ab.alpha, ab.beta, theta_elec);
}

// 验证主函数
int main() {
    // 测试用例1:三相对称电流,幅值1A,相位0°
    // ia=1, ib=-0.5, ic=-0.5 → 期望 i_alpha=1, i_beta=0
    float ia1 = 1.0f, ib1 = -0.5f, ic1 = -0.5f;
    AlphaBeta ab1 = clark_transform(ia1, ib1, ic1);
    printf("Clark[1]: alpha=%.4f, beta=%.4f (期望 1.0000, 0.0000)\n", ab1.alpha, ab1.beta);

    // 测试用例2:theta=0时,dq应与αβ一致
    DQ dq1 = park_transform(ab1.alpha, ab1.beta, 0.0f);
    printf("Park[theta=0]: d=%.4f, q=%.4f (期望 1.0000, 0.0000)\n", dq1.d, dq1.q);

    // 测试用例3:theta=90°(PI/2),αβ=(1,0)旋转后 → d=0, q=-1
    DQ dq2 = park_transform(1.0f, 0.0f, PI/2.0f);
    printf("Park[theta=90]: d=%.4f, q=%.4f (期望 0.0000, -1.0000)\n", dq2.d, dq2.q);

    // 测试用例4:完整链路,ia=1, ib=-0.5, ic=-0.5, theta=PI/3
    // 手算: alpha=1, beta=0 → d=cos60=0.5, q=-sin60=-0.8660
    DQ dq3 = abc_to_dq(1.0f, -0.5f, -0.5f, PI/3.0f);
    printf("abc_to_dq[theta=60]: d=%.4f, q=%.4f (期望 0.5000, -0.8660)\n", dq3.d, dq3.q);

    return 0;
}

编译与运行

gcc -o foc_transform foc_transform.c -lm
./foc_transform

验证方法与通过条件

程序输出应与注释中的期望值一致(浮点误差在±0.0001内):

  • Clark验证:三相对称电流 (1, -0.5, -0.5) 变换后 α=1, β=0,符合等幅值变换定义。
  • Park零角验证:θ=0 时 dq 轴与 αβ 轴重合,d=α, q=β。
  • Park旋转验证:αβ=(1,0) 旋转 90° 后,d=0, q=-1,验证旋转方向为 q 轴滞后 d 轴 90°(符合常用FOC约定)。
  • 完整链路验证:θ=60° 时 d=0.5, q=-0.8660,与手算结果一致。

若四项输出均匹配期望值,则变换实现正确,可用于后续FOC电流环控制。

常见问题

  • 等幅值 vs 等功率变换:本实现采用等幅值(系数2/3),若需等功率变换,系数改为 √(2/3),且Park矩阵需相应调整。
  • 角度单位:theta_elec 必须为弧度。若传感器输出为角度,需先乘以 PI/180 转换。
  • 浮点精度:嵌入式环境建议使用 float 并开启 -O2 优化;若需更高精度可改用 double。