3. Clark变换:三相坐标系到两相静止坐标系
好,咱们进入FOC的第一个核心数学变换——Clark变换。
说实话,我刚接触FOC时,看到这些坐标变换公式,第一反应是「这玩意儿有必要吗?」。后来在项目里调一个三相电机,电流波形乱七八糟,我才真正体会到:不把三相系统简化成两相,你根本没法下手去控制。
Clark变换,说白了就是把三相静止坐标系(a, b, c)下的物理量,映射到两相静止坐标系(α, β)下。为什么这么做?因为三相耦合太强了,控制起来麻烦。两相就清爽很多。
3.1 为什么要做Clark变换?
你想想看,电机三相绕组在空间上相差120°。通电后,每一相都会产生磁动势。三个磁动势叠加在一起,合成一个旋转磁场。
问题来了:我们想控制的是这个合成磁场的大小和方向。但直接控制三相电流,你得同时调三个变量,而且它们之间还有耦合。这就像同时牵三匹马,方向还不一样,累不累?
Clark变换就是帮你把这三匹马「合并」成两匹。α轴和β轴互相垂直,没有耦合。控制起来就简单多了。
核心思想:Clark变换保持磁动势不变,只是换了个坐标系来看它。
3.2 数学推导
咱们从物理直觉出发。假设三相电流为 ia、ib、ic,它们满足:
ia + ib + ic = 0
这是星形连接的特点,三相电流之和为零。嗯,这个条件很重要,后面会用到。
现在,我们要找到两个正交的轴——α轴和β轴。通常让α轴与a轴重合,β轴超前α轴90°。
根据磁动势等效原则,可以推导出:
| 变换 | 公式 |
|---|---|
| 正向Clark变换 (abc → αβ) |
iα = ia iβ = (ia + 2·ib) / √3 |
| 反向Clark变换 (αβ → abc) |
ia = iα ib = (-iα + √3·iβ) / 2 ic = (-iα - √3·iβ) / 2 |
我的小技巧:实际项目中,我习惯用「等幅值变换」版本。也就是上面这个。还有一种「等功率变换」,系数不同,但原理一样。我个人觉得等幅值更直观,调试时好理解。
为什么会得到这个形式?我简单说下推导思路。
设三相电流产生的磁动势为:
F = N·(ia + ib·ej120° + ic·ej240°)
其中N是有效匝数。把这个复数展开成实部和虚部,实部对应α轴,虚部对应β轴。再利用 ia + ib + ic = 0 消去一个变量,就能得到上面的公式。
嗯,数学上就是这么回事。你不需要每次都推导一遍,但理解背后的物理意义很重要。
3.3 代码实现
纸上谈兵差不多了,咱们直接上代码。我用C语言写,因为嵌入式里最常用。
// Clark变换:三相电流 → 两相静止坐标系
// 输入:ia, ib, ic(三相电流)
// 输出:*alpha, *beta(两相电流)
void clark_transform(float ia, float ib, float ic,
float *alpha, float *beta)
{
// 正向Clark变换(等幅值版本)
*alpha = ia;
*beta = (ia + 2.0f * ib) / 1.7320508f; // 1.732 = sqrt(3)
// 注意:这里没有用到ic,因为 ia+ib+ic=0
// 但实际采样时,我建议三个都采,用来做校验
}
我曾经踩过的坑:一开始我只采两相电流,第三相用公式算。结果有一次电流传感器坏了,我浑然不知,电机跑起来抖得像筛子。后来我改成三相都采,算完Clark变换后,再用反向变换算回去,对比原始值。一旦偏差超过阈值,立刻报错。这个冗余设计救了我好几次。
反向变换的代码:
// 反向Clark变换:αβ → abc
void inv_clark_transform(float alpha, float beta,
float *ia, float *ib, float *ic)
{
float sqrt3 = 1.7320508f;
*ia = alpha;
*ib = (-alpha + sqrt3 * beta) * 0.5f;
*ic = (-alpha - sqrt3 * beta) * 0.5f;
}
你看,代码就这么几行。但实际工程里,有几个细节要注意:
- 浮点运算精度:嵌入式MCU的FPU如果支持单精度,就用float。如果没FPU,考虑用Q格式定点数。我之前在STM32F103上做过,用Q15格式,速度能快3倍。
- 查表优化:√3/2 这种常数,可以预计算好。我习惯在初始化时算好,避免运行时反复除。
- 溢出保护:如果电流很大,α和β可能超出ADC范围。记得做饱和处理。
3.4 实际项目中的经验
我记得有一次做伺服驱动器,电流环频率设到20kHz。Clark变换本身计算量不大,但加上后面的Park变换、PI调节器、SVPWM,整个控制周期就很紧张了。
我当时做了个优化:把Clark和Park变换合并成一个函数。因为Park变换需要角度信息,而Clark变换不需要。合并后,省掉了一次中间变量的存储和读取,大概省了200ns。在20kHz下,这就是4%的CPU时间,挺可观的。
代码大概长这样:
// 合并的 Clark + Park 变换
void clark_park_transform(float ia, float ib, float ic,
float theta,
float *id, float *iq)
{
float alpha, beta;
float cos_t = cosf(theta);
float sin_t = sinf(theta);
// Clark
alpha = ia;
beta = (ia + 2.0f * ib) * 0.57735f; // 1/sqrt(3)
// Park
*id = alpha * cos_t + beta * sin_t;
*iq = -alpha * sin_t + beta * cos_t;
}
我的建议:初学者先分开写,逻辑清晰。等调通了,再考虑合并优化。过早优化是万恶之源——这话是Knuth说的,我觉得很有道理。
3.5 小结
Clark变换是整个FOC的基石。它把三相耦合系统,变成了两相正交系统。虽然数学上只是简单的线性变换,但物理意义很深刻——它让我们能用更直观的方式看待电机的磁场。
下一章,我们会在这个基础上做Park变换,把静止的αβ坐标系,转到旋转的dq坐标系。到那时,你就能理解为什么FOC能像控制直流电机一样控制交流电机了。
嗯,先消化这些。代码写一遍,跑一跑,比看十遍都管用。