前言
上一章我们通过Clark 变换,把三相电流 Iu,Iv,Iw 变成了两相静止坐标系下的电流 Iα,Iβ。到这里,电机电流从 “三相耦合” 变成了 “两相正交”,计算简单了很多,但依然是交流量—— 大小随时间正弦变化,没法用简单的 PID 直接稳控。
FOC 之所以能把无刷电机变得像直流电机一样好控制,核心全靠 Park 变换。
本章我们一次性讲透:
- Park 变换到底在干什么
- d/q 轴分别代表什么物理意义
- 电角度 θ 从哪来、怎么算
- 完整公式推导 + 两种写法
- 浮点 / 定点代码直接可用
- 工程里 90% 的人都会踩的坑
读完这一章,你才算真正摸到 FOC 的核心逻辑。
1. Park 变换到底解决了什么问题?
先一句话总结:
Park 变换:把 αβ 静止坐标系,变换到 dq 旋转坐标系,让交流量变成直流量。
展开说:
- αβ 坐标系:固定在定子上,不动
- dq 坐标系:固定在转子上,跟着转子一起旋转
当你站在 “旋转的转子” 视角去看电流:
- 原来随时间正弦波动的 Iα,Iβ
- 会变成两个稳定不变的直流分量 Id,Iq
交流变直流意味着什么?
- 可以用普通 PI 调节器直接控制
- 可以做到完全解耦:磁场归磁场,力矩归力矩
- 控制简单、稳定、响应快、低速平滑
这就是 FOC 能吊打方波驱动的根本原因。
2. d 轴与 q 轴的物理意义
对表贴式永磁同步电机 PMSM(我们常用的 BLDC 绝大多数都是这种):
d 轴(direct axis)直轴与转子永磁体磁场方向一致对应:励磁分量
q 轴(quadrature axis)交轴超前 d 轴 90° 电角度对应:转矩分量
控制目标极其清晰:
- Id=0:弱磁控制以外,默认都让 d 轴电流为 0,不削弱磁场,效率最高
- Iq:想力气大就加大 Iq,想刹车就减小甚至反向
这就是经典的:
Id=0 FOC 控制策略
3. 电角度 θ 是整个变换的 “钥匙”
Park 变换本质是矢量旋转,旋转多少度,由电角度 θ决定。
电角度怎么来?
θ 的作用:
它代表当前转子磁场指向的角度,决定了 dq 坐标系相对于 αβ 坐标系旋转了多少。
没有 θ,Park 变换无从谈起。θ 不准 → FOC 直接抖、啸叫、无力、发热。
4. Park 变换标准公式推导
4.1 变换关系
从 αβ 静止坐标系,逆时针旋转 θ,得到 dq 旋转坐标系:
5. 反 Park 变换(FOC 输出必备)
电流环计算完 Vd,Vq 之后,要变回 αβ 给 SVPWM 用,这就是反 Park。
公式:
6. 完整代码实现(浮点版)
6.1 Park 变换
#include "math.h" /** * @brief Park 变换: αβ → dq * @param Iα, Iβ: 两相静止电流 * @param theta: 电角度(弧度) * @param Id, Iq: 输出直流量 */ void Park_Transform(float Ialpha, float Ibeta, float theta, float *Id, float *Iq) { float sin_theta = sinf(theta); float cos_theta = cosf(theta); *Id = Ialpha * cos_theta + Ibeta * sin_theta; *Iq = -Ialpha * sin_theta + Ibeta * cos_theta; }6.2 反 Park 变换
/** * @brief 反Park变换: dq → αβ * @param Vd, Vq: 电压指令 * @param theta: 电角度(弧度) * @param Valpha, Vbeta: 输出静止坐标系电压 */ void Inv_Park(float Vd, float Vq, float theta, float *Valpha, float *Vbeta) { float sin_theta = sinf(theta); float cos_theta = cosf(theta); *Valpha = Vd * cos_theta - Vq * sin_theta; *Vbeta = Vd * sin_theta + Vq * cos_theta; }7. 定点优化版(无 FPU 单片机适用)
对 STM32F103 等资源紧张的 MCU,可以用正弦余弦表 + Q15 定点:
// 正弦余弦表(θ:0~360°,精度1°), Q15格式 const int16_t sin_table[] = { // 自行填入 0~359° 的 sin*32767 }; #define GET_SIN(deg) sin_table[deg%360] #define GET_COS(deg) sin_table[(deg+90)%360] void Park_Fixed(int16_t Ialpha, int16_t Ibeta, uint16_t theta_deg, int16_t *Id, int16_t *Iq) { int32_t sin_theta = GET_SIN(theta_deg); int32_t cos_theta = GET_COS(theta_deg); *Id = ((int32_t)Ialpha * cos_theta + (int32_t)Ibeta * sin_theta) >> 15; *Iq = ((int32_t)-Ialpha * sin_theta + (int32_t)Ibeta * cos_theta) >> 15; }工程建议:
- 有 FPU(F4/F7/H7/G4)直接用浮点,简单好调
- 无 FPU 用查表法,速度极快
8. 为什么变换后 Id、Iq 是直流(最关键的理解)
举个直观例子:
- 你站在地面(αβ)看风车叶片,位置一直在变,是交流
- 你坐在风车转子上(dq)一起转,叶片相对你不动,是直流
对应到电机:
- 、 随电角度正弦波动
- 用 θ 同步旋转后,波动被 “抵消” 了
- 输出的 、 变成恒定直流
于是:
- 用 PI 控制器去稳 Id、Iq
- 就像控制简单直流电机一样轻松
这就是 FOC 的数学魔法。
9. 工程高频踩坑
9.1 θ 角度方向反了
现象:
- 电机一转就啸叫、抖动、电流巨大
- 改方向也没用
原因:
- 电角度 θ 递增方向与转子实际旋转方向相反
解决:
theta = -theta;或反序 Hall 计算角度。
9.2 sin/cos 角度单位不统一
- 代码里用弧度,计算时用角度
- 结果完全错乱
统一规则:
- C 语言 math.h:sinf/cosf 一律用弧度
- 霍尔 / 编码器:先转弧度再传入
9.3 dq 轴定义反了
有些资料 / 电机库定义:Iq=Iαsinθ+Iβcosθ符号不一样,会导致:
- 力矩方向相反
- 电机飞车、失控
解决:整套 FOC 坐标系从头到尾保持一致,不要混用多家库公式。
9.4 角度延迟未补偿
编码器读取、ADC 采样、运算都需要时间θ 已经变了,你还用旧角度→ 电流环相位滞后 → 低速抖、高速弱
高端 FOC 都会做:角度前馈补偿 / 观测器相位补偿
9.5 Id 没有置 0
表贴式电机默认 Id=0如果你给 Id 一个随机初始值会出现:
- 力矩小
- 电流大
- 发热严重
- 效率极低
10. 完整 FOC 电流环结构
完整的电流环流程:
- ADC 采样三相电流 Iu,Iv,Iw
- Clark 变换→ Iα,Iβ
- Park 变换→ Id,Iq
- PI 闭环:
- Idref=0
- Iqref 为力矩指令
- 输出 Vd,Vq
- 反 Park 变换→ Vα,Vβ
- 送入SVPWM生成三相 PWM
这就是标准Id=0 FOC 控制架构。
11. 本章总结
Park 变换是 FOC 真正的灵魂,核心就 4 点:
- 功能:αβ 静止 → dq 旋转,交流变直流
- 核心变量:电角度 θ,决定旋转角度
- 物理意义:
- Id:励磁,默认 0
- Iq:转矩,控制力气
- 公式:必须记住一对正变换 + 反变换,代码直接套用
到这里,FOC 最难的数学部分已经全部结束。