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。你调试电流环时,脑子里要时刻有这个图。
4.7 常见问题与避坑
最后,我总结几个实际项目中容易出问题的地方:
| 问题 | 现象 | 原因 | 解决办法 |
|---|---|---|---|
| 角度零点偏移 | i_d和i_q有交流分量 | 编码器零位未对齐 | 做角度校准,或软件补偿 |
| 变换系数不一致 | 电流幅值不对,PI参数失效 | 等幅值与等功率混用 | 统一用一种,推荐等幅值 |
| sin/cos计算延迟 | 高速时电流畸变 | 角度更新不够快 | 用查表法或硬件加速 |
| 三相采样顺序错 | Clark输出异常 | ADC采样时序没对齐 | 确保三相同时采样或补偿 |
我曾经遇到一个特别隐蔽的问题: 某次调试,电机低速时电流波形正常,一上高速就开始抖。查了两天,发现是Park变换里用的角度是上一拍的,延迟了一个PWM周期。高速时角度变化快,一拍延迟就导致dq轴耦合。后来改成预测角度,问题解决。所以,角度更新的实时性,比你想象的重要得多。