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。