坐标变换(下):Park变换
好,咱们接着聊坐标变换。上一节我们把三相静止的ABC坐标系,变到了两相静止的αβ坐标系。这一步做完,电机模型从三个变量变成了两个,但问题还没彻底解决——αβ坐标系下的电流仍然是正弦波。
你想想看,正弦波意味着什么?意味着电流在不停变化。控制一个变化的东西,总归不如控制一个恒定的东西来得方便。这就是Park变换要干的事——把两相静止的αβ坐标系,旋转到跟转子磁场同步的两相旋转坐标系上。
说白了,就是把交流量变成直流量。这样PID控制器就能像控制直流电机一样,去控制永磁同步电机了。
Park变换的数学推导
先看数学。Park变换的输入是αβ坐标系下的两个分量:Iα和Iβ。输出是dq坐标系下的两个分量:Id和Iq。
变换的核心思想很简单:把αβ坐标系旋转一个角度θ。这个θ就是转子磁场的电角度。
公式长这样:
Id = Iα * cos(θ) + Iβ * sin(θ)
Iq = -Iα * sin(θ) + Iβ * cos(θ)
嗯,其实就是个旋转矩阵。我刚开始学的时候,总觉得这个公式应该反过来——为什么Id是cos乘Iα加sin乘Iβ?后来画了个矢量图才明白:
- α轴和d轴的夹角是θ
- 把Iα和Iβ分别投影到d轴上,再求和,就是Id
- 把Iα和Iβ分别投影到q轴上,再求和,就是Iq
投影嘛,就是点乘。所以本质上,Park变换就是两个向量的点乘运算。
关键点:Park变换的输入是αβ电流和电角度θ。θ必须准确,否则变换出来的Id、Iq就是错的。我在项目中遇到过因为编码器安装偏差导致θ不准,结果电机抖得像筛子一样。
Park变换的代码实现
代码实现非常直接。我习惯用浮点数,但在资源受限的MCU上,也可以用定点数。先看浮点版本:
typedef struct {
float Id;
float Iq;
} DQ_Current;
DQ_Current Park_Transform(float I_alpha, float I_beta, float theta) {
DQ_Current dq;
float sin_theta = sinf(theta);
float cos_theta = cosf(theta);
dq.Id = I_alpha * cos_theta + I_beta * sin_theta;
dq.Iq = -I_alpha * sin_theta + I_beta * cos_theta;
return dq;
}
这段代码没什么花哨的。但有个细节要注意:sinf和cosf在有些MCU上跑得很慢。我建议用查表法,或者用Cordic算法。具体用哪种,取决于你的MCU有没有硬件三角函数单元。
我的经验:在STM32F4上,用硬件FPU的sinf/cosf大概需要几十个时钟周期。但在Cortex-M0上,软件实现的sinf可能要几百个周期。这时候查表法更靠谱,256点的正弦表,精度够用,速度也快。
定点数版本呢?我贴一个常用的Q15格式实现:
typedef struct {
int16_t Id; // Q15格式
int16_t Iq; // Q15格式
} DQ_Current_Q15;
DQ_Current_Q15 Park_Transform_Q15(int16_t I_alpha, int16_t I_beta, int16_t theta_q15) {
DQ_Current_Q15 dq;
int16_t sin_theta, cos_theta;
// 从正弦表查值
sin_theta = sin_table[(theta_q15 >> 7) & 0x1FF];
cos_theta = cos_table[(theta_q15 >> 7) & 0x1FF];
// Q15乘法,结果右移15位
dq.Id = (int16_t)(((int32_t)I_alpha * cos_theta + (int32_t)I_beta * sin_theta) >> 15);
dq.Iq = (int16_t)((-(int32_t)I_alpha * sin_theta + (int32_t)I_beta * cos_theta) >> 15);
return dq;
}
注意Q15乘法后要右移15位,不然数值会溢出。我曾经在这个坑里摔过一次——忘记移位,结果Id和Iq直接飞了,电流环完全失控。
反Park变换
有正变换就有反变换。反Park变换的作用,是把dq坐标系下的电压指令,变回αβ坐标系下的电压指令。这样SVPWM才能用。
公式也很对称:
V_alpha = Vd * cos(θ) - Vq * sin(θ)
V_beta = Vd * sin(θ) + Vq * cos(θ)
你看,跟正变换的区别就是符号变了。正变换里Id的公式是加号,反变换里V_alpha的公式是减号。这个细节容易搞混,我建议你直接记住:正变换的矩阵是旋转矩阵的逆矩阵,而旋转矩阵的逆就是它的转置。
代码实现:
typedef struct {
float V_alpha;
float V_beta;
} AlphaBeta_Voltage;
AlphaBeta_Voltage Inv_Park_Transform(float Vd, float Vq, float theta) {
AlphaBeta_Voltage ab;
float sin_theta = sinf(theta);
float cos_theta = cosf(theta);
ab.V_alpha = Vd * cos_theta - Vq * sin_theta;
ab.V_beta = Vd * sin_theta + Vq * cos_theta;
return ab;
}
注意:反Park变换的输入是电压指令Vd和Vq,不是电流。有些初学者会把电流Id、Iq直接拿去反变换,结果出来的电压值完全不对。记住:电流环的输出是电压,电压经过反Park变换后给SVPWM。
Park变换的物理意义
聊完了数学和代码,咱们说说物理意义。
为什么叫Park变换?因为有个叫Park的人提出的。但更重要的是,它揭示了电机控制的本质:
- d轴:直轴,与转子磁场方向对齐。控制Id就是控制励磁分量。
- q轴:交轴,与转子磁场方向垂直。控制Iq就是控制转矩分量。
在表贴式永磁同步电机(SPMSM)中,通常让Id=0,只控制Iq。这样转矩和电流就是线性关系,控制起来特别简单。
但在内置式永磁同步电机(IPMSM)中,需要利用磁阻转矩,所以Id不能为0。这时候就要用最大转矩电流比(MTPA)控制,Id和Iq都要算。
嗯,这些是后面章节的内容了。你现在只需要记住:Park变换把交流变直流,让PID有了用武之地。
总结一下:
- Park变换把αβ坐标系旋转到dq坐标系,旋转角度是转子电角度θ
- 正变换:αβ电流 → dq电流
- 反变换:dq电压 → αβ电压
- θ的精度直接影响变换结果,编码器校准很重要
- 代码实现简单,但要注意三角函数的速度和精度
下一节,咱们聊聊SVPWM——怎么把αβ电压变成真正的PWM波,驱动逆变器。那一步才是真正让电机转起来的关键。