2026/10/19 22:17:43

FOC控制过程详解:从电流采样到SVPWM的落地调试指南

FOC控制过程详解:从电流采样到SVPWM的落地调试指南 做电机控制这些年被问得最多的问题就是FOC控制过程到底是怎么一步步跑起来的。说实话硬件方案成熟之后FOC并不算难它更像一道逻辑题只要把相电流、转子角度、电压指令这几件事在坐标系里理顺剩下的工作就是在每个PWM周期里按固定顺序算完十几条公式。真正难的是每一步背后的原因以及调试时碰到电流发散、启动反转、切换冲击这些实际问题要怎么定位。这篇文章我就把FOC控制过程完整拆开从电流采样到SVPWM输出从PI参数估算到无感启动与闭环切换写成一份可以直接照着落地调试的工程笔记适合刚接触FOC的嵌入式软件工程师也适合想从方波控制转向FOC的硬件和算法开发者。1. FOC的实质把交流电机当直流电机来骗FOC的英文全称是Field-Oriented Control直译就是磁场定向控制。不少人第一次听到这个概念以为它是一种很玄的电机驱动波形生成技术其实它本质上是在做一个控制目标的翻译工作把电机本体里三相交流电 旋转磁场的复杂问题转换成两个直流电流分量的简单问题。用一句话概括我的理解FOC不是在千方百计生成正弦波形而是在把交流电机当作一台直流电机来控制。1.1 三相电流为什么不能直接作为PI的反馈很多人一开始会疑惑三相电流本身就是正弦波PI控制器专门跟踪直流量的为什么不能直接给三个PI呢这就涉及到控制对象的本质。三相定子绕组在空间上相隔120度通入相位依次相差120度的正弦电流后气隙里才会形成匀速旋转的磁场。这三个相电流的频率等于电频率它随转速一直在变如果用PI去跟踪一个正弦信号跟踪精度直接受PI带宽限制带宽再高也会出现相位滞后。更麻烦的是转速升高时正弦频率也在升高相当于让控制器去追一个永远追不上的目标。还有一层数学上的简化三相电流并不是独立的。星形连接下ia ib ic 0知道任意两相第三相就等于负的和。真正产生转矩的并不是某一相电流的大小而是三相电流合成的定子电流空间矢量is。这个矢量有自己的幅值和方向控制目标从让三相电流分别等于三个正弦量变成让合成电流矢量等于期望的矢量本身就是一次降维。后面的Clark变换和Park变换全都是围绕这个空间矢量展开的。1.2 d-q轴电流控制目标与电机物理的对应关系把转子永磁体的磁极方向定义为d轴也就是直轴再沿旋转方向超前90度定义为q轴也就是交轴。于是定子电流矢量is被分解成两个分量id和iq。id作用在d轴方向它不产生有效转矩只影响气隙磁场强弱iq作用在q轴方向和转子磁场相互作用这才是真正产生电磁转矩的分量。对于表贴式永磁同步电机Ld约等于Lq电磁转矩近似正比于iq对于内嵌式永磁电机Ld和Lq有明显差异还会多出一项磁阻转矩这时可以通过让id为负值来提升单位电流的转矩输出也就是MTPA最大转矩电流比控制。从控制角度看无论哪种电机核心动作都收敛到两件事让id收敛到目标值让iq跟随速度环给出的转矩电流指令。目标值从变化的交流量变成稳定的直流量之后PI控制器终于可以做它最擅长的事了。1.3 转子磁链角度整个FOC的基准坐标d-q坐标是旋转坐标它跟着转子磁链的电角度θe走。这个角度是整个FOC的基准坐标角度不准id和iq就没有解耦iq指令里会混入id成分表现为同样的电流指令下转矩变小、电流偏大甚至出现电流震荡。我第一版FOC调试时就吃过这个亏电流环参数怎么调都共振后来发现编码器安装时零位偏了几度角度误差直接把整个控制环路带偏了。角度误差并不是差不多就行。实测中3度左右的角度误差在额定工况下就能让电流明显变大10度以上的误差会把正向转矩算成负向电机直接反转。所以我的调试顺序永远是第一步抓角度波形确认旋转方向和零位第二步才谈电流环。有传感器的FOC直接读编码器角度乘以极对数无感FOC靠反电动势观测器估计不管哪种方案角度这条线如果没打通后面调得再久也是白费。2. 一条完整的FOC链路从ADC到SVPWM到底走了多少步每个PWM周期内FOC做的事情可以压缩成一条固定顺序的链路采样相电流、偏置校正、坐标变换、电流环PI、逆变换、SVPWM生成六路PWM。初学者最容易把SVPWM理解成生成正弦波的一种调制方式其实它只是一套把αβ坐标系下的电压指令翻译成逆变器开关序列的规则。下面把这条链路一步步拆开。2.1 Clark与Park静止坐标和旋转坐标的切换Clark变换把三相静止坐标系变换到两相静止坐标系。采用等幅值变换且在星形连接、三相平衡的前提下工程里最常用的简化公式是iα iaiβ (1 / √3) * (ib - ic)如果三相不平衡或者在三角形连接下需要用完整公式包括ia、ib、ic三项的系数别为了一点运算量牺牲鲁棒性。Park变换把两相静止坐标变换到两相旋转坐标公式如下id iα * cos(θe) iβ * sin(θe)iq -iα * sin(θe) iβ * cos(θe)这个符号约定不是唯一的但一定要和逆Park变换保持配套。我建议统一用上面的约定并规定iq为正时对应正向电磁转矩。逆Park变换是这样的vα vd * cos(θe) - vq * sin(θe)vβ vd * sin(θe) vq * cos(θe)注意PI输出得到的是vd和vq它们不是直接加在电机端线上而是要经过逆Park变换变成αβ坐标系下的分量再送到SVPWM环节。这个PI输出电压指令、逆变器去执行电压指令的层次关系一定要清楚否则很容易把SVPWM和逆变器概念搅在一起。2.2 SVPWM的扇区判断与矢量作用时间计算逆变器有六个开关管同一桥臂上下管不能同时导通只看上管状态的话八个基本开关状态里包含六个有效矢量U1到U6和两个零矢量U0、U7。这六个有效矢量把平面分成六个扇区SVPWM要解决两个问题判断参考电压矢量落在哪个扇区以及在这个扇区里让相邻的两个矢量各作用多少时间。扇区判断有现成做法根据vα和vβ计算三个中间量U1 vβU2 -vβ √3 * vαU3 -vβ - √3 * vαU1大于0时A记为1U2大于0时B记为1U3大于0时C记为1N A 2B 4C。根据N值就能映射出实际扇区这个映射我在DSP和普通MCU的FOC库里都见过只是命名和符号略有差异核对一次自己手上的矢量图就行。确定扇区后一种直观且不易出错的矢量作用时间计算方式是用几何法。先求参考电压矢量的幅值Umag和角度θ再求它在当前扇区内的相对角度γ于是相邻两个矢量的作用时间分别是T1 √3 * Umag * sin(60° - γ) * Ts / UdcT2 √3 * Umag * sin(γ) * Ts / UdcT0 Ts - T1 - T2就是零矢量作用时间。如果T1加T2已经超过Ts说明进入了过调制区必须按比例同时缩小T1和T2。这个饱和度处理一定要放在写入PWM比较寄存器之前否则生成出来的占空比可能超过定时器周期波形直接乱套。有人会问为什么用这种带sin的计算而不是网上常见的X、Y、Z查表法其实那些查表法本质上就是把上面的三角函数公式按六个扇区展开后的代数化简为了省掉FPU上的sin和atan2运算。如果你的主控带FPU几何法完全够用而且不容易写错如果是不带FPU的8位或者低端MCU再去用查表法。实际工程里追求的是可维护性和不出错不是把代码写得越绕越好。2.3 一个可以照着写的FOC主循环伪代码把整条链路串起来控制中断里做的事情就是下面这个固定流程可以当作模板来用。每个PWM周期进入一次频率通常取10kHz到20kHz。// 每个PWM周期Ts内执行一次 void FOC_ISR(void) { // 1. 读取ADC采样结果ia、ib ia ADC_GetChannel(ADC_CH_A); ib ADC_GetChannel(ADC_CH_B); ic -(ia ib); // 2. 偏置校正 ia - ia_offset; ib - ib_offset; // 3. 角度更新有编码器时直接用无感时用观测器结果 theta omega * Ts; // 4. Clark变换 i_alpha ia; i_beta (1.0f / SQRT3) * (ib - ic); // 5. Park变换 id i_alpha * cos(theta) i_beta * sin(theta); iq -i_alpha * sin(theta) i_beta * cos(theta); // 6. 电流环PI需要做输出限幅和反饱和处理 vd PI_Update(pid_d, id_ref, id); vq PI_Update(pid_q, iq_ref, iq); // 7. 逆Park变换 v_alpha vd * cos(theta) - vq * sin(theta); v_beta vd * sin(theta) vq * cos(theta); // 8. SVPWM扇区判断、计算比较值、更新定时器 svpwm_update(v_alpha, v_beta); }这套伪代码是FOC的最小全集。实际项目里还要在链路上挂速度环、弱磁控制、MTPA、死区补偿、故障保护甚至观测器更新但无论加多少东西主链路的相对顺序不要乱动。我见过有人把PI输出限幅漏了结果积分疯狂累加一恢复指令电机猛冲一下这种问题在代码评审里一定要盯住反饱和处理。3. 电流环设计与PI整定先算后调再不行就扫电流环是FOC的内环速度环再漂亮内环带宽跟不上外环全白搭。很多初学者一上来就乱试PID三个参数我强烈不建议这么做。电流环的对象是一阶R-L电路PI参数完全可以先按电机参数估出一个能直接跑的初值再用示波器微调。3.1 用电机参数算出PI初值表贴式永磁同步电机的d-q轴电压方程在忽略耦合项并做一定简化后可以写成vd R * id L * did/dtvq R * iq L * diq/dt ω * ψfd轴和q轴本质上都是R-L一阶惯性对象电流环PI开环传递函数和电机传递函数相乘后如果把PI零点放在电机极点位置也就是满足Ki / Kp R / L那么闭环就近似成一阶惯性环节开环增益Kp / L直接决定电流环带宽。于是估算公式很简单Kp L * ωcKi R * ωc其中ωc是期望的电流环带宽单位是rad/s。举个例子一台小型无人机电机相电阻R是0.25Ω相电感L是35μH想把电流环带宽做到3000rad/s也就是大约477Hz那么Kp 35e-6 * 3000 0.105Ki 0.25 * 3000 750。单位分别是V/A和V/(A·s)。PWM频率20kHz时Ts只有50微秒电流环带宽建议取1000到3000rad/s。超过5000rad/s后会非常难稳因为数字控制本身有1到2个PWM周期的延迟带宽拉太高相位裕度会快速掉光表现为高频抖动和噪音。这个公式估算出来的初值只要电感误差不是特别离谱通常已经能稳定运行接下来再用波形去修正。3.2 实测调参时让波形开口有了初值后不建议直接带着负载调最实用的做法是锁轴调试。把电机轴机械锁死电流环给定一个iq阶跃用示波器看实际iq波形。电流环作为一阶系统阶跃理论上不应该超调所以看到超调通常意味着环路延迟补偿不到位或采样噪声过大。我把常见的现象和调整方向总结在下面这张表里实际调试时可以对着排查现象可能原因调整方向响应太慢iq像斜坡一样慢慢爬Kp偏小带宽不够增大Kp保持Ki/Kp比例不变阶跃出现明显超调和振铃环路延迟导致相位裕度不足整体降低增益或者增大PWM频率缩短Ts稳态有小幅高频抖动采样噪声或零漂检查采样时刻、偏置校准必要时加一阶低通指令方向切换时冲击大PI输出限幅或积分饱和检查限幅逻辑加入反饱和处理注意一个反直觉的点电流环出现超调时很多人下意识去减小Kp但如果是相位裕度不足引起的减小Kp确实能稳定代价是带宽变低、动态变慢。我一般会在保证Ki/Kp R/L的前提下整体缩放增益把带宽压到一个稳定且有余量的值然后观察dq轴电流在阶跃下的表现。d轴电流阶跃比q轴更干净因为d轴没有反电动势项干扰所以调参时先看id回路的波形会更直观。3.3 闭环带宽与延迟预算数字FOC从采样到PWM更新天然存在延迟ADC采样需要时间算法计算需要时间占空比更新通常要等下一个PWM周期才能生效。这个总延迟大约1到2个PWM周期直接影响电流环能实现的最高带宽。工程上用经验公式粗估带宽上限大约在1/(3Ts)附近20kHz PWM时约6600rad/s实际建议留足裕量只用到一半左右。也就是说把PWM频率从8kHz提到16kHz或20kHz不只是让波形更细腻而是直接给电流环争取了带宽空间。高带宽的电流环能让外环速度环更稳定也让无感观测器在更高动态下不失步。所以设计FOC系统时PWM频率通常是先定好的约束条件电流环带宽跟着PWM频率走速度环带宽再比电流环带宽低一个数量级左右这样整个级联系统才有足够的稳定裕度。4. 无感FOC从静止到高速启动流程和过渡逻辑无感FOC不用编码器也不用霍尔硬件成本最低但代价是低速时反电动势太小观测器几乎没法用。所以从静止到高速必须拆成几个阶段每个阶段的控制策略都不同。这一步是很多无感方案一转就飞的重灾区。4.1 初始位置预定位还是高频脉冲注入转子静止时如果不知道磁极方向直接给一个旋转磁场轻载下也许能转起来重载或带机械设备时大概率反转或堵转。工程上最简单可靠的做法是预定位也叫alignment给定一个固定的d轴电流比如0.5到1倍额定电流持续200到500毫秒让转子被定子磁场强行拉到已知角度。这个方法的缺点很直白启动瞬间电机会先动一下对静摩擦小的水泵、风机没影响但精密传动或压缩机这类不允许反转的应用就不行。如果要求静止启动且不能有明显位移就得用高频信号注入法。向估计的d轴注入高频电压信号利用d-q电感差异带来的电流响应差异来判断转子位置。这个方案实现复杂度和计算量都高不少很多无感算法只在低速段用高频注入中高速切换回反电动势观测器。我的选型习惯是允许启动瞬间动一下用预定位要求静止启动优先上高频注入介于两者之间的先用预定位跑通整个闭环链路再升级到注入法。4.2 开环强拉阶段的电流控制有了初始位置接下来进入开环强拉阶段。所谓开环指的是控制用的角度不来自观测器而是来自软件积分器生成的给定电频率ωe。这个频率会按照预设斜坡从零往上爬同时电流指令幅值也从启动值逐步提升。即使角度是假的电流环仍然正常工作d-q轴坐标系跟着软件角度旋转把真实电流强行拽成期望的id和iq。这个阶段最关键的是斜坡速率。电频率增加太快转子实际速度跟不上就会出现失步电流瞬间失控太慢又会让启动过程显得拖沓。加速度斜率主要看负载惯量我做过的一个风机项目里电频率每秒加15Hz左右约1秒内从0拉到15Hz电频率带负载实测电流波动很小。如果设备有大惯量负载斜坡要更缓必要时分段处理先慢速建立电流再逐渐提升频率最后在切换点附近把加速度进一步调小。4.3 切换闭环时如何避免咯噔一声无感FOC最惊心动魄的时刻就是开环强拉切换到闭环观测器的那一下。切换瞬间如果角度跳变电流环看到的坐标系突然转过一个角度电流冲击会非常剧烈轻则电机咯噔一声重则过流保护触发。我的做法是让观测器从开环阶段就一直运行只估计不参与控制。在强拉过程中持续比较开环给定角度θ_open和观测器估计角度θ_obs使用一个低成本的逻辑两个角度的差值要先经过2π跳变处理变成连续差值再判断是否小于阈值比如5度以内并且维持一小段时间才允许切换。切换时不要硬切而是做一个软过渡窗口控制角度θ_ctrl (1-k) * θ_open k * θ_obsk从0平滑变化到1窗口持续几十到几百毫秒。这样即使两个角度有一点残余误差电流冲击也会被平滑掉而不是瞬间全部接过来。切换完成后速度环才真正接管把速度指令和观测器速度估计做闭环。整个启动过程中电流环一直在线所以最怕的不是电流环不稳而是角度源切换那一瞬间的坐标系错动。把这个过渡做平滑了无感启动的成功率会大幅提升。5. 实际工程中容易忽略的坑采样、死区、零漂写完算法链路和启动逻辑再聊几个我在实际调试中踩过、也帮别人排查过的问题。这些问题单看都不难但藏在波形异常背后时很容易让人在PI参数上白费几天时间。5.1 电流采样时刻到底该选在哪最常用的低压方案是双电阻下桥臂采样也就是在两个下管导通时通过采样电阻上的压降获得相电流。采样时刻要选在下管导通区间的稳定中点通常就是PWM计数器到达周期值或零点的时刻对应三角载波的顶点。这时三相下桥臂在七段式调制里都处于导通或续流状态采样窗口最大电流纹波也最小ADC采出来的值最有代表性。如果采样时刻没选好正好落在开关沿附近ADC结果会混入振铃和开关噪声。比较诡异的一种现象是空载时电流波形很干净一加载就全是毛刺很多人以为是干扰加滤波、换地线折腾半天最后发现是占空比增大把采样窗口挤到了开关沿附近。解决思路不是加滤波器而是确认ADC触发源由定时器同步触发并且采样保持时间足够而不是用软件延时去碰运气。单电阻采样方案更复杂一个PWM周期里的电流信息要靠多个采样点重构在低占空比和高占空比区域都存在天然盲区小型电机项目里能用双电阻或三电阻采样就不要为了省一个采样电阻去选单电阻方案。5.2 偏置校准为什么必须开机做电流采样链路的运放偏置不可能精准为零。偏置不消除id和iq里会始终叠加一个固定偏置电机在零指令时也可能有电流表现为空载发热、轻微抖动甚至低速时有一点点动静。这个问题和PI参数没有关系所以很多人调参数调到头也解决不了。正确的做法是在PWM禁止输出、电机不供电的状态下多次采样电流通道取平均把结果保存为偏置值。注意要在上电一段时间、电源稳定之后再校准如果环境温度变化大最好定期重校。我遇到过一次很隐蔽的问题换了运放芯片之后零漂比原来大了几十毫安空载电流波形看起来还正常但带上负载后力矩波动明显。排查到最后才发现是偏置变了从那以后我都在初始化流程里加开机自校准并保留运行中空闲时定时重校的接口。5.3 死区补偿和调制策略的配合死区是防止桥臂直通故意插入的等待时间但它会造成输出电压误差和电流波形畸变。死区时间固定时误差大小与电流方向相关电流方向为正实际输出电压会低于指令方向为负实际输出电压高于指令。低速轻载时电流接近零的区域会出现平台畸变听上去像电机噪音变大转矩脉动明显增加。死区补偿的计算式很简单补偿电压为v_comp -sign(i) * Tdead * Udc / Ts实现时方向判断很关键。电流接近零时sign()会来回跳如果盲目补偿补偿量反而成了扰动源。我习惯加一个滞回或者零区阈值电流绝对值小于某个门槛时不补偿超过门槛才按方向补偿。另外一个容易忽略的点是死区补偿要和调制策略配合七段式SVPWM和五段式DPWM的零矢量插入方式不同死区误差分布也不一样切换调制策略时必须重新验证补偿参数。最后说说我的实际体会。FOC调通的关键不在公式背得多熟而在能不能把每个环节的波形拿过来和理论对照。我调过的每一套FOC方案几乎都经历过电流震荡、启动反转、切换冲击这些必经之路每次排查问题按这个顺序来先怀疑角度、再怀疑采样、最后才怀疑控制器参数能省掉大量无效劳动。如果你正被某个电流震荡折磨可以先把转子机械锁死单独调电流环内环稳了再去碰速度环和无感切换。这个流程我反复用十次里有九次能快速定位问题。FOC本质上不是什么高深莫测的算法它只是一套需要耐心对待坐标变换和控制时序的工程实践把主链路顺序和每个环节的物理意义都弄清楚后剩下的就是按部就班地调、测、验证。