4. STM32硬件平台选型
上一章我们聊了Clark变换,把三相静止的ABC坐标系,硬生生掰成了两相静止的αβ坐标系。但问题来了——电机转子是转的,你αβ轴还杵在那儿不动,这怎么玩?
Park变换就是来解决这个问题的。它把两相静止的αβ坐标系,映射到两相旋转的dq坐标系上。说白了,就是让坐标系跟着转子一起转。这样一来,原本在αβ轴上忽大忽小的正弦波电流,到了dq轴上就变成了直流分量。直流分量PID好控啊,这就是FOC能实现精准控制的底层逻辑。
4.1 从几何直观理解Park变换
先别急着看公式。我带你从几何上理解一下。
想象你站在地面上(静止的αβ坐标系),看着一个旋转的圆盘(转子)。圆盘上有个标记点(磁链方向)。你看到的标记点位置,每时每刻都在变。但如果你也站到圆盘上,跟着它一起转,那标记点在你眼里就是静止的。
Park变换干的就是这件事。它把αβ轴上的分量,投影到旋转的dq轴上。d轴(直轴)与转子磁链方向对齐,q轴(交轴)超前d轴90度电角度。
这里有个关键点:Park变换需要知道转子当前的电角度θ。这个θ从哪里来?从编码器或者霍尔传感器来,或者从无感观测器估算出来。没有θ,Park变换就是无源之水。
4.2 Park变换公式推导
好,我们来推公式。其实很简单,就是二维坐标系旋转。
假设αβ坐标系中有一个向量,它在α轴上的分量为Iα,在β轴上的分量为Iβ。现在我们要把这个向量投影到旋转了θ角的dq坐标系上。
从几何关系上看:
- d轴分量 = Iα × cos(θ) + Iβ × sin(θ)
- q轴分量 = -Iα × sin(θ) + Iβ × cos(θ)
写成矩阵形式就是:
[Id] [cos(θ) sin(θ)] [Iα]
[Iq] = [-sin(θ) cos(θ)] [Iβ]
这就是Park变换的完整公式。你仔细看,它其实就是个旋转矩阵。我当年第一次看到这个公式时,心想:就这?对,就这。但就是这简单的旋转,把交流控制变成了直流控制。
4.3 逆Park变换
有正变换就有逆变换。FOC控制中,我们算出了dq轴上的给定电压Ud和Uq,但最终要送到SVPWM模块去驱动电机,而SVPWM需要的是αβ坐标系下的电压。所以需要逆Park变换:
[Uα] [cos(θ) -sin(θ)] [Ud]
[Uβ] = [sin(θ) cos(θ)] [Uq]
注意看,逆变换矩阵是正变换矩阵的转置。因为旋转矩阵是正交矩阵,逆矩阵等于转置矩阵。这个性质在代码实现时很有用——你只需要存一份cos和sin值,正变换和逆变换都能用。
4.4 代码实现:STM32上的Park变换
直接上代码。我习惯用浮点运算,清晰易懂。如果你对性能有极致要求,可以改成定点数,但浮点对于STM32G4或H7系列来说完全够用。
/**
* @brief Park变换:αβ -> dq
* @param Ialpha: α轴电流
* @param Ibeta: β轴电流
* @param theta: 转子电角度(弧度)
* @param Id: 输出的d轴电流指针
* @param Iq: 输出的q轴电流指针
*/
void Park_Transform(float Ialpha, float Ibeta, float theta,
float *Id, float *Iq)
{
float cos_theta = arm_cos_f32(theta);
float sin_theta = arm_sin_f32(theta);
*Id = Ialpha * cos_theta + Ibeta * sin_theta;
*Iq = -Ialpha * sin_theta + Ibeta * cos_theta;
}
/**
* @brief 逆Park变换:dq -> αβ
* @param Ud: d轴电压给定
* @param Uq: q轴电压给定
* @param theta: 转子电角度(弧度)
* @param Ualpha: 输出的α轴电压指针
* @param Ubeta: 输出的β轴电压指针
*/
void Inv_Park_Transform(float Ud, float Uq, float theta,
float *Ualpha, float *Ubeta)
{
float cos_theta = arm_cos_f32(theta);
float sin_theta = arm_sin_f32(theta);
*Ualpha = Ud * cos_theta - Uq * sin_theta;
*Ubeta = Ud * sin_theta + Uq * cos_theta;
}
4.5 代码验证:用数据说话
代码写完了,怎么验证对不对?我建议你造一组已知数据来测试。
假设我们有一个单位向量,在αβ坐标系中指向45度方向:
- Iα = 0.7071
- Iβ = 0.7071
现在转子电角度θ = 45°(0.7854 rad)。按照Park变换,这个向量应该完全投影到d轴上,q轴分量为0。我们来算:
Id = 0.7071 × cos(45°) + 0.7071 × sin(45°)
= 0.7071 × 0.7071 + 0.7071 × 0.7071
= 0.5 + 0.5 = 1.0
Iq = -0.7071 × sin(45°) + 0.7071 × cos(45°)
= -0.7071 × 0.7071 + 0.7071 × 0.7071
= -0.5 + 0.5 = 0.0
结果完美:Id=1.0,Iq=0.0。这说明当电流向量与d轴对齐时,q轴没有分量,所有能量都用来产生磁链。反过来,如果电流向量与d轴垂直,则Id=0,Iq=1.0,所有能量都用来产生转矩。
这就是FOC的底层逻辑:通过控制Id和Iq,独立控制磁链和转矩。
4.6 坐标系变换全景图
为了让你对整个变换链路有个全局认识,我画了张图:
4.7 常见坑与避坑指南
我在项目中遇到过几个Park变换相关的坑,分享给你:
- 角度单位搞混: 有人用度,有人用弧度。代码里统一用弧度,否则cos/sin算出来全是错的。我曾经调试一个电机,转起来抖得像筛糠,查了半天发现是角度单位没统一。
- 角度更新不及时: Park变换和逆Park变换用的θ必须是同一个时刻的值。如果你在中断里先算Park变换,然后被高优先级任务打断,回来再算逆Park变换时θ已经变了,那控制就会乱。我的做法是在一个临界区内同时完成正变换和逆变换。
- 浮点精度问题: 对于低端STM32(比如F103),浮点运算慢,可以考虑用Q15或Q31定点数。但对于G4/H7系列,硬件FPU加持下浮点运算几乎不占时间,直接用float就行。
4.8 小结
Park变换说白了就是一个旋转矩阵,把静止的αβ坐标系转到跟着转子转的dq坐标系。它让交流量变成了直流量,为后续的PI控制铺平了道路。
代码实现上,记住三点:角度用弧度、正逆变换用同一组cos/sin、角度更新要原子操作。把这三点做到位,Park变换这块就不会出问题。