第3章 坐标变换基础:Clark变换、Park变换与逆变换
坐标变换,说白了就是换个角度看电机。你想想看,电机里转的是三相正弦电流,可我们做控制时,最习惯处理的是直流量。怎么把交流变成直流?这就是Clark和Park要干的事。
我刚开始接触FOC时,觉得这堆变换公式就是数学游戏。直到有一次在项目里调试电流环,发现PI参数怎么调都抖——后来才发现是坐标变换的相位算错了。嗯,从那以后我再也不敢小看这章内容了。
3.1 为什么需要坐标变换?
三相永磁同步电机的数学模型,在三相静止坐标系下是时变的、强耦合的。电感矩阵随转子位置变化,反电动势也是正弦量。直接在这上面做控制,难度很大。
坐标变换的核心思想:把三相交流量,映射到与转子同步旋转的坐标系中,变成直流量。这样一来,控制问题就简化为对直流量的调节,PI控制器就能派上用场了。
核心逻辑链:
三相交流 → Clark变换 → 两相静止(αβ) → Park变换 → 两相旋转(dq) → 直流量 → 简单控制
下面这张图,把整个变换流程串起来了。我建议你先看明白这个框架,再往下抠细节。
3.2 Clark变换(三相静止 → 两相静止)
Clark变换,也叫3/2变换。它把三相坐标系下的电流 \( i_u, i_v, i_w \),映射到两相静止坐标系下的 \( i_\alpha, i_\beta \)。
数学上,它基于一个前提:三相系统是平衡的,即 \( i_u + i_v + i_w = 0 \)。
3.2.1 变换公式
等幅值变换(最常用)的公式如下:
i_α = i_u
i_β = (i_u + 2*i_v) / √3
写成矩阵形式更清晰:
| i_α | | 1 -1/2 -1/2 | | i_u |
| i_β | = | 0 √3/2 -√3/2 | | i_v |
(系数 2/3 在等幅值变换中已隐含)
我的习惯:实际代码里,我一般只采样两相电流(比如 i_u 和 i_v),第三相用 i_w = -i_u - i_v 算出来。省一个ADC通道,还少一路噪声。
3.2.2 等幅值 vs 等功率
这里有个坑,我当年踩过。Clark变换有两种主流约定:
| 变换类型 | 前向系数 | 逆变换系数 | 特点 |
|---|---|---|---|
| 等幅值变换 | 2/3 | 1 | αβ幅值与三相幅值相同,调试直观 |
| 等功率变换 | √(2/3) | √(2/3) | 变换前后功率守恒,理论推导方便 |
我个人推荐:工程实现用等幅值变换。为什么?因为你在示波器上看电流波形时,αβ幅值直接等于相电流幅值,一眼就能看出对错。等功率变换虽然数学上更优雅,但调试时多一道换算,容易晕。
我曾经踩过的坑:有一次把等幅值和等功率的系数搞混了,电流环PI参数怎么算都不对。后来发现是Clark变换系数错了,导致反馈值偏小,控制器输出偏大,系统一直在震荡。从那以后,我每次写变换代码,都会在注释里把系数来源写清楚。
3.3 Park变换(两相静止 → 两相旋转)
Clark变换之后,我们有了 \( i_\alpha, i_\beta \)。但它们还是正弦量。要变成直流量,需要引入转子位置角 \( \theta \)。
Park变换,就是把αβ坐标系旋转到与转子磁极同步的dq坐标系上。
3.3.1 变换公式
i_d = i_α * cos(θ) + i_β * sin(θ)
i_q = -i_α * sin(θ) + i_β * cos(θ)
矩阵形式:
| i_d | | cos(θ) sin(θ) | | i_α |
| i_q | = | -sin(θ) cos(θ) | | i_β |
这里的 θ,就是转子电角度。通常由编码器或霍尔传感器提供,或者通过观测器估算。
物理意义:
- i_d(直轴电流):与转子磁场方向一致,控制磁通
- i_q(交轴电流):与转子磁场方向垂直,控制转矩
在表贴式PMSM中,通常控制 i_d = 0,只调节 i_q 来控制转矩。这就是经典的 id=0 控制。
3.4 逆变换
控制算法算出来的是 dq 电压指令 \( u_d^*, u_q^* \),但最终要加到电机上的还是三相电压。所以需要逆变换:先 Park⁻¹,再 Clark⁻¹。
3.4.1 Park逆变换(dq → αβ)
u_α = u_d * cos(θ) - u_q * sin(θ)
u_β = u_d * sin(θ) + u_q * cos(θ)
其实就是Park变换矩阵的转置。因为Park变换矩阵是正交矩阵,逆矩阵等于转置矩阵。
3.4.2 Clark逆变换(αβ → UVW)
等幅值变换下的逆变换:
u_u = u_α
u_v = -0.5 * u_α + (√3/2) * u_β
u_w = -0.5 * u_α - (√3/2) * u_β
你想想看,这里 u_u + u_v + u_w = 0,正好满足三相平衡条件。
3.5 代码实现要点
下面给出一份C语言实现,我习惯把这些函数写成内联,放在头文件里。因为FOC控制周期很短(通常50μs~100μs),函数调用开销能省则省。
// 假设已经定义好浮点类型 float
#define SQRT3 1.7320508075688772f
#define INV_SQRT3 0.5773502691896258f
// Clark变换:输入 i_u, i_v,输出 i_alpha, i_beta
// 等幅值变换,i_w = -i_u - i_v
static inline void clark_transform(float i_u, float i_v,
float *i_alpha, float *i_beta) {
*i_alpha = i_u;
*i_beta = (i_u + 2.0f * i_v) * INV_SQRT3;
}
// Park变换:输入 i_alpha, i_beta, theta,输出 i_d, i_q
static inline void park_transform(float i_alpha, float i_beta, float theta,
float *i_d, float *i_q) {
float c = cosf(theta);
float s = sinf(theta);
*i_d = i_alpha * c + i_beta * s;
*i_q = -i_alpha * s + i_beta * c;
}
// Park逆变换:输入 u_d, u_q, theta,输出 u_alpha, u_beta
static inline void park_inverse(float u_d, float u_q, float theta,
float *u_alpha, float *u_beta) {
float c = cosf(theta);
float s = sinf(theta);
*u_alpha = u_d * c - u_q * s;
*u_beta = u_d * s + u_q * c;
}
// Clark逆变换:输入 u_alpha, u_beta,输出 u_u, u_v, u_w
static inline void clark_inverse(float u_alpha, float u_beta,
float *u_u, float *u_v, float *u_w) {
*u_u = u_alpha;
*u_v = -0.5f * u_alpha + 0.5f * SQRT3 * u_beta;
*u_w = -0.5f * u_alpha - 0.5f * SQRT3 * u_beta;
}
性能优化建议:
- 如果MCU没有硬件浮点单元(FPU),考虑用查表法或CORDIC算法计算 sin/cos
- θ 的更新建议用定点数累加,避免每次调用都做浮点除法
- 把 cos(θ) 和 sin(θ) 提前算好,一次计算多次使用
3.6 常见问题与避坑
- 相位顺序搞反:U、V、W的接入顺序必须与编码器零位对齐。我见过有人把UVW接反了,结果Clark变换出来的αβ相位反了180°,电机根本转不起来。
- θ 的零点校准:Park变换用的 θ 是电角度,不是机械角度。极对数 p 对时,θ_elec = p * θ_mech。编码器安装偏差会导致 θ 有固定偏移,需要做一次零点标定。
- 浮点精度问题:在低端MCU上,float 的精度有限。长时间运行后,θ 累加误差会越来越大。建议定期用外部信号(如霍尔边沿)对 θ 做硬同步。
- 变换系数一致性:Clark和Park的系数必须前后统一。前向用等幅值,逆变换也必须用等幅值。混用会导致幅值缩放,控制量不准。
我曾经踩过的坑:有一次在量产阶段,发现同一批板子有的电机转得顺,有的抖得厉害。排查了两天才发现——编码器安装时,有一批的Z信号偏移了30°电角度。结果Park变换用的 θ 始终差30°,id/iq 解耦不彻底,转矩脉动很大。从那以后,我要求产线每块板子都做零点自校准。
3.7 小结
坐标变换是FOC的数学基础,也是最容易出错的地方。Clark变换把三相变两相,Park变换把静止变旋转。逆变换把控制结果送回三相世界。
记住三个关键点:
- 变换系数要统一(推荐等幅值)
- θ 要准确且与硬件对齐
- 代码实现要高效,适合实时控制
把这些搞扎实了,后面的电流环、速度环设计才能站得住脚。