2. Clark变换与Park变换:坐标变换的数学推导与DSP实现技巧

坐标变换,说白了就是SVPWM的数学基础。没有它,你根本没法把三相电压转换成空间矢量。我刚开始接触这个的时候,也觉得公式挺唬人的,但真正用起来,其实就那么几步。

2.1 为什么需要坐标变换?

三相电机有三相绕组,每相电流都是正弦波,相位差120度。你想想看,三个变量同时变化,控制起来多麻烦。能不能把它们简化一下?

坐标变换就是干这个的。它把三相静止坐标系(a,b,c)先变到两相静止坐标系(α,β),再变到两相旋转坐标系(d,q)。这样一来,交流量就变成了直流量,控制就简单多了。

核心思想: 把时变的三相系统,映射到非时变的两相旋转坐标系中。说白了,就是让控制器只处理直流信号。

2.2 Clark变换:从三相到两相静止

Clark变换的公式长这样:

Iα = Ia
Iβ = (Ia + 2*Ib) / √3

等等,你是不是觉得少了Ic?没错,因为Ia + Ib + Ic = 0,所以Ic = -Ia - Ib。实际用的时候,我们只需要采样两相电流就够了。

我在项目中遇到过一个问题:采样电阻的噪声会直接耦合到Iα和Iβ上。后来我加了个一阶低通滤波,效果好了很多。

等幅值变换 vs 等功率变换

变换类型 系数 特点
等幅值变换 2/3 变换后幅值不变,SVPWM常用
等功率变换 √(2/3) 变换前后功率守恒,电机模型常用

我个人习惯用等幅值变换,因为SVPWM的扇区判断和矢量作用时间计算都是基于幅值的,用等幅值变换更直观。

2.3 Park变换:从静止到旋转

Park变换把αβ坐标系旋转θ角度,得到dq坐标系:

Id = Iα * cosθ + Iβ * sinθ
Iq = -Iα * sinθ + Iβ * cosθ

这里θ是转子位置角,通常由编码器或霍尔传感器提供。如果没有位置传感器,那就得用观测器估算了——那是另一个话题。

小技巧: 在DSP里实现Park变换时,sinθ和cosθ可以查表得到。我一般用256点的正弦表,精度够用,计算也快。

2.4 避免三角函数计算瓶颈

三角函数计算是DSP的噩梦。一次sin或cos运算可能要几十个时钟周期,而SVPWM的开关频率通常是10kHz~20kHz,每个周期都要算好几次。你想想看,这得多浪费CPU资源。

怎么优化?我总结了三个方法:

  1. 查表法: 预先算好sin和cos值,存到数组里。运行时直接查表,速度极快。
  2. CORDIC算法: 只用移位和加法就能算三角函数,适合没有硬件乘法器的低端DSP。
  3. 角度归一化: 把角度映射到0~2π范围内,避免大角度计算带来的精度损失。

我曾经在一个项目里用过CORDIC,但发现精度不够,后来还是换回了查表法。嗯,这里要注意:查表法的精度取决于表的大小,256点一般够用,如果要求高,可以做到512点或1024点。

2.5 DSP实现技巧:定点数 vs 浮点数

很多DSP没有硬件浮点单元,比如TI的C2000系列早期型号。这时候就得用定点数来模拟浮点运算。

我常用的做法是Q格式:

// Q15格式:1位符号位 + 15位小数位
// 表示范围:-1 ~ 0.999969
int16_t sin_table[256];  // Q15格式的正弦表

// 查表时,角度索引 = (θ & 0xFF)  // 取低8位
int16_t sin_val = sin_table[theta & 0xFF];
int16_t cos_val = cos_table[theta & 0xFF];

// Park变换,全部用定点乘法
int32_t id = (int32_t)ialpha * cos_val + (int32_t)ibeta * sin_val;
int32_t iq = -(int32_t)ialpha * sin_val + (int32_t)ibeta * cos_val;

// 结果右移15位,还原为Q15格式
id = id >> 15;
iq = iq >> 15;

注意: 定点乘法容易溢出。比如两个Q15数相乘,结果是Q30格式,需要右移15位才能回到Q15。如果中间结果超过32位,就得用64位累加器,或者分段计算。

2.6 代码示例:完整的Clark+Park变换

下面是一个完整的C语言实现,适合在DSP上跑:

// 输入:三相电流ia, ib(Q15格式),转子角度theta(0~65535对应0~2π)
// 输出:id, iq(Q15格式)
void clark_park(int16_t ia, int16_t ib, uint16_t theta, 
                int16_t *id, int16_t *iq) {
    // Clark变换
    int16_t ialpha = ia;  // Iα = Ia
    int16_t ibeta = (ia + 2 * ib) / 1732;  // Iβ = (Ia+2Ib)/√3, √3≈1.732
    
    // 查表得到sin和cos
    uint8_t idx = (theta >> 8) & 0xFF;  // 取高8位作为索引
    int16_t sin_theta = sin_table[idx];
    int16_t cos_theta = cos_table[idx];
    
    // Park变换
    int32_t tmp_id = (int32_t)ialpha * cos_theta + (int32_t)ibeta * sin_theta;
    int32_t tmp_iq = -(int32_t)ialpha * sin_theta + (int32_t)ibeta * cos_theta;
    
    *id = tmp_id >> 15;
    *iq = tmp_iq >> 15;
}

这段代码我用了好几年,在多个项目里验证过。唯一要注意的是,角度theta的表示方式——我用的是0~65535对应0~2π,这样取高8位就能得到0~255的索引,非常方便。

2.7 知识体系总览

下面这张图总结了坐标变换的整个流程:

坐标变换知识体系 三相静止 (a,b,c) Clark变换 两相静止 (α,β) Park变换 两相旋转 (d,q) 关键点: • Clark变换:Ia + Ib + Ic = 0,只需采样两相电流 • Park变换:需要转子位置角θ,由编码器或观测器提供 • 三角函数优化:查表法(256点)或CORDIC算法 • 定点数实现:Q15格式,注意乘法溢出问题 图2-1 坐标变换流程与关键点

2.8 避坑指南

最后,分享几个我踩过的坑:

  • 角度对齐问题: 编码器的零位和电机的电气零位要对齐,否则Park变换出来的dq分量会有直流偏置。我曾经因为这个原因,电机低速时抖得厉害,查了两天才发现是角度没对齐。
  • 采样时序: 电流采样要在PWM的中间时刻进行,避开开关噪声。我一般用PWM的ADC触发功能,在载波波谷处采样。
  • 数值范围: 定点数运算时,中间结果很容易溢出。建议先用浮点仿真一遍,看看各个变量的动态范围,再确定Q格式的位数。

好了,坐标变换这部分就讲到这里。记住,Clark和Park变换是SVPWM的基石,一定要吃透。下一节我们会用这些变换结果来合成空间电压矢量,那才是SVPWM的核心。


专注资料整理