
1. 从零吃透FOC为什么它成了电机控制的分水岭搞电机控制的人绕不开FOC这三个字母。Field-Oriented Control磁场定向控制也有人叫矢量控制。我第一次接触它的时候脑子里全是问号——明明一个直流无刷电机给它通电就能转为什么非要搞这么复杂后来做了一段时间的伺服项目才明白让电机转起来和让电机听话完全是两码事。FOC解决的核心问题是把交流电机的定子电流分解成两个正交分量一个用来产生磁场d轴一个用来产生转矩q轴。这个思路的来源其实很朴素——直流电机之所以好控制就是因为它的励磁和转矩在物理上是解耦的你调励磁电流不影响转矩调转矩电流不影响磁场。交流电机没有换向器和电刷定子绕组通的是交流电磁场和转矩天然耦合在一起控制起来就麻烦。FOC做的事情就是通过坐标变换把交流电机“伪装”成直流电机来控。这个“伪装”的过程涉及两次坐标变换。第一次是Clarke变换把三相电流从abc静止坐标系变到αβ静止坐标系相当于把三个分量压缩成两个。第二次是Park变换把αβ坐标系旋转到dq旋转坐标系旋转角度就是转子磁链的位置角θ。经过这两步原本随时间变化的三相正弦电流在dq坐标系下变成了两个直流量——id和iq。直流量意味着什么意味着你可以用最简单的PI控制器去调它不用考虑频率变化带来的相位滞后问题。这就是FOC的精髓所在。它把“控制交流量”这个难题转化成了“控制直流量”这个简单问题。代价是你需要知道转子的实时位置需要快速的电流采样需要一套能实时跑坐标变换和PI调节的算力。十年前做FOC得用DSP或者FPGA成本高得吓人。现在一颗几十块钱的STM32G4或者国产的GD32就能把整个FOC算法跑得飞起这也是为什么最近几年FOC突然在中小功率应用里遍地开花。适合看这篇内容的人我大致分三类。第一类是做嵌入式软件出身想从方波驱动升级到FOC的工程师你可能已经会用六步换向让电机转起来但发现低速抖动、噪音大、效率低想搞清楚FOC到底怎么落地。第二类是做硬件或者系统设计的需要理解FOC对采样电路、驱动电路、MCU外设的具体要求好做方案选型和成本评估。第三类是在校学生或者刚入行的新人想找一个完整的FOC实现路径从理论到代码到调试不走弯路。不管你是哪一类接下来的内容都会从实际工程角度出发把FOC拆开揉碎讲清楚。2. FOC整体方案设计与核心思路拆解2.1 为什么是“电流环速度环”的双环结构FOC的典型控制结构是双闭环内环电流环外环速度环。这个结构不是拍脑袋定的背后有明确的控制理论依据。电流环是内环它的响应速度必须远快于速度环。一般电流环的带宽在1kHz到5kHz之间速度环的带宽在50Hz到200Hz之间两者差一个数量级以上。为什么因为电流环负责的是“力矩”这个物理量而力矩直接决定加速度。如果你想让电机快速响应速度指令电流必须能瞬间跟上。如果电流环慢了速度环给出的电流指令还没被执行速度环就已经开始积分饱和了整个系统就会振荡。从工程实现角度电流环的采样周期通常在10μs到50μs也就是20kHz到100kHz的PWM频率下每个PWM周期做一次电流采样和PI调节。速度环的周期可以慢很多1ms到5ms都行因为机械惯量本身就大速度变化没那么快。这种“快内环、慢外环”的设计在控制理论里叫串级控制好处是每一层只需要管好自己的事内环把电流控稳了外环就只需要操心速度不用管电流的细节。我见过一些新手直接把速度环和电流环放在同一个中断里跑PWM频率20kHz速度环也20kHz。结果就是速度环的积分项疯狂累积电机一启动就过冲然后来回振荡。后来把速度环降到1kHz问题立刻消失。这个坑很典型核心原因就是没有理解串级控制里“带宽分离”的原则。2.2 有感和无感位置信息从哪来FOC必须知道转子位置角θ这是整个算法的前提。获取θ的方式分两大类有传感器和无传感器。有传感器方案里最常见的是霍尔传感器和编码器。霍尔传感器便宜但分辨率低每个电周期只有6个状态角度误差最大能到30度。用霍尔做FOC必须做角度插值否则转矩脉动会很大。编码器分辨率高增量式编码器动辄几千线配上四倍频角度精度可以做到0.1度以内但成本也上去了。磁编码器是折中方案像AS5047、MT6701这类芯片SPI接口直接输出14位角度价格十几块钱精度够用安装也简单现在很多中小功率FOC方案都用它。无感方案就复杂多了。没有传感器你得从电机的电压和电流里“猜”出转子位置。主流方法有三种反电动势观测器、滑模观测器、高频注入。反电动势观测器适合中高速因为反电动势幅值和转速成正比转速太低时信号太弱信噪比不够。滑模观测器鲁棒性强对参数变化不敏感但有个讨厌的抖振问题得用边界层或者高阶滑模来抑制。高频注入适合零速和低速原理是给电机注入一个高频电压信号利用凸极效应d轴和q轴电感不同来提取位置信息但高速时反电动势会淹没高频响应所以通常和反电动势观测器配合使用低速用高频注入高速切到反电动势。实际项目里无感FOC的启动是最头疼的。零速时反电动势为零观测器完全失效你得先“盲启”——用一段预设的电压矢量把电机拖到一定转速等反电动势起来了再切换到闭环。这个切换点选不好电机就会失步或者抖动。我一般会在启动阶段用电流闭环强拖电流给定小一点让电机平稳加速等转速到了额定转速的5%到10%再切到观测器闭环。切换时要做角度和速度的平滑过渡不能硬切。2.3 采样时机为什么PWM中点采样最靠谱电流采样是FOC的“眼睛”采不准后面所有计算都是白搭。三相电流理论上只需要采两相第三相可以通过基尔霍夫电流定律算出来iaibic0。但实际电路中采样电阻的放置位置和运放电路会引入误差所以有些方案会采三相用三路ADC同时转换。采样时机的选择非常关键。PWM驱动电机时MOS管在开关电流里全是开关噪声。如果你在MOS管开关瞬间采样采到的全是尖峰。正确的做法是在PWM周期的中点采样因为中点时刻上下桥臂的开关状态稳定电流也稳定。具体来说对于中心对齐的PWM模式计数器从0往上数到峰值再往下数到0。在计数器等于峰值的时候所有下桥臂MOS管导通或者上桥臂导通取决于你的驱动逻辑电流流过采样电阻这时候采到的就是真实的相电流。STM32的定时器有个专门的触发输出信号可以配置成在计数器峰值时触发ADC硬件自动完成采样不占用CPU时间。这里有个细节采样电阻上的电压信号需要经过运放放大再送到ADC。运放的带宽要足够否则电流变化快的时候运放输出跟不上采到的值就滞后了。一般选带宽1MHz以上的运放增益根据采样电阻和ADC量程来定。比如采样电阻0.01Ω电流10A时压降0.1VADC量程3.3V增益就是33倍。但增益太大会引入噪声所以采样电阻不能太小一般选0.005Ω到0.05Ω之间。3. 核心细节解析与实操要点3.1 Clarke变换和Park变换的代码实现Clarke变换的公式很简单iα ia iβ (ia 2*ib) / √3这是等幅值变换的形式也有等功率变换的形式区别在于系数。等幅值变换下变换前后电流幅值不变但功率会差一个系数。工程上一般用等幅值变换因为电流环的给定值直接对应相电流幅值比较直观。Park变换需要转子角度θid iα*cos(θ) iβ*sin(θ) iq -iα*sin(θ) iβ*cos(θ)反Park变换用于把电压指令从dq变回αβvα vd*cos(θ) - vq*sin(θ) vβ vd*sin(θ) vq*cos(θ)这些三角函数计算在MCU上跑如果用浮点运算STM32F4系列有FPU单次sin/cos大概几十个时钟周期20kHz的PWM频率下完全够用。如果用定点MCU比如STM32F1或者一些国产M0核的芯片就得用查表法或者CORDIC算法来加速。查表法要注意表的大小和插值方式表太小角度分辨率不够表太大占Flash。我一般用1024点的正弦表配合线性插值角度精度能到0.1度以内够用了。代码实现上我习惯把Clarke和Park写成一个函数输入是三相电流和角度输出是id和iq。这样在电流环中断里调用一次就行逻辑清晰。注意变量类型如果用的是浮点直接float如果用定点Q格式要统一一般用Q15范围-1到1对应电流的标幺值。3.2 电流环PI调节器的参数整定电流环的PI参数决定了整个FOC系统的响应速度和稳定性。整定方法有两种理论计算和实验调试。理论计算需要知道电机的电阻R和电感L。电流环的被控对象可以近似为一阶惯性环节传递函数是1/(LsR)。PI控制器的传递函数是KpKi/s。闭环带宽ωc和PI参数的关系是Kp ωc * L Ki ωc * Rωc一般取PWM角频率的1/10到1/5。比如PWM频率20kHz角频率是2π20000≈125600 rad/sωc取12560 rad/s也就是2kHz带宽那么Kp12560LKi12560*R。但理论计算有个问题它假设逆变器是理想电压源实际逆变器有死区、管压降、开关延迟这些都会影响电流环的实际性能。所以理论算出来的参数只能作为起点最终还得在实验台上调。实验调试的方法先把Ki设为0只加Kp从小到大慢慢加直到电流波形开始出现振荡然后退回一点记下这个Kp值。然后加Ki也是从小到大加直到电流响应出现超调或者低频振荡再退回一点。最后微调Kp和Ki让电流阶跃响应的上升时间在1ms以内超调小于10%。我自己的经验是对于大多数中小功率PMSMKp在0.5到5之间Ki在100到2000之间具体看电机参数和PWM频率。如果电机电感很小比如空心杯电机Kp要小一点否则电流纹波会很大。如果电机电感很大比如大功率工业电机Kp可以大一些响应更快。3.3 SVPWM的实现与死区补偿SVPWM是FOC里把电压指令转换成PWM占空比的关键环节。它的核心思想是用两个相邻的基本电压矢量和零矢量在一个PWM周期内合成任意方向的电压矢量。相比SPWMSVPWM的直流电压利用率高15%左右而且谐波特性更好。SVPWM的实现步骤先判断电压矢量在哪个扇区然后计算两个相邻矢量的作用时间最后分配给三个定时器的比较寄存器。扇区判断可以用Clarke变换后的vα和vβ通过比较它们的符号和大小关系来确定。作用时间的计算涉及√3和除法在MCU上可以用查表或者定点运算来加速。死区是逆变器的固有特性。上下桥臂不能同时导通否则会短路所以必须在开关切换时插入一段死区时间通常是几百纳秒到几微秒。死区会导致输出电压和指令电压有偏差特别是在电流过零附近偏差最大会造成电流波形畸变和转矩脉动。死区补偿的方法有几种一种是基于电流方向的补偿根据相电流的符号在PWM占空比上加减一个死区补偿量。另一种是基于电压反馈的补偿通过检测实际输出电压来修正。工程上常用第一种简单有效。补偿量的大小等于死区时间除以PWM周期再乘以直流母线电压。比如死区1μsPWM周期50μs补偿量就是2%的占空比。但死区补偿有个坑电流过零时电流方向不确定补偿方向可能来回跳变反而引入振荡。所以很多方案会在电流过零附近不补偿或者用滞环比较器来稳定补偿方向。我一般会在电流绝对值小于某个阈值比如额定电流的5%时把补偿量线性衰减到零这样过渡比较平滑。4. 实操过程与核心环节实现4.1 硬件平台搭建与关键器件选型一套完整的FOC硬件平台包括MCU、栅极驱动器、MOSFET、电流采样电路、位置传感器有感方案、电源。MCU选型上STM32G4系列是专门为电机控制设计的内置了运放、比较器、高速ADC和定时器一片就能搞定整个FOC系统。如果成本敏感STM32F1系列也能跑FOC但主频只有72MHz没有FPU得用定点运算代码优化要花不少功夫。国产的GD32、APM32也有对应的型号引脚和STM32兼容价格便宜不少。栅极驱动器选型要看MOSFET的栅极电荷和开关频率。比如IR2103、EG2133这类半桥驱动器自带死区插入和自举电路用起来很方便。如果是低压小功率应用也可以用集成MOSFET的驱动芯片比如DRV8313体积小外围简单。MOSFET选型主要看耐压、导通电阻和栅极电荷。耐压要留至少20%的余量比如24V母线选30V或者40V的MOSFET。导通电阻决定了导通损耗栅极电荷决定了开关损耗。开关频率高的时候栅极电荷的影响更大要选Qg小的型号。电流采样电路有两种方案电阻采样和霍尔电流传感器。电阻采样便宜精度也够但要注意共模电压范围。如果采样电阻放在下桥臂和地之间共模电压就是地运放好选。如果放在母线或者相线上共模电压高得用差分运放或者隔离运放。霍尔传感器贵一些但隔离性好安装方便适合大电流场合。4.2 STM32 FOC代码框架与中断配置我用STM32G431搭过一套FOC平台主频170MHzPWM频率20kHz电流环和速度环都在中断里跑。代码框架大致分三层底层驱动定时器、ADC、SPI、中间件坐标变换、PI、SVPWM、应用层状态机、通信。定时器配置成中心对齐模式ARR值根据PWM频率和主频计算。比如170MHz主频20kHz PWMARR 170e6 / (2 * 20e3) 4250。计数器从0数到4250再数回0一个周期是50μs。ADC配置成由定时器的触发输出信号触发在计数器等于ARR的时候采样这样采到的就是PWM中点时刻的电流。中断服务函数里做这些事情读取ADC电流值、做Clarke和Park变换、电流环PI调节、反Park变换、SVPWM计算、更新比较寄存器。整个过程要在50μs内完成所以代码要尽量精简。三角函数用查表除法用乘法代替能省不少时间。速度环放在另一个定时器中断里1kHz频率做速度PI调节输出iq的给定值。速度计算用编码器的位置差分注意要做低通滤波否则速度反馈噪声很大。4.3 无感FOC的滑模观测器实现滑模观测器的核心是一个电流观测器用电机电压方程来估计反电动势再从反电动势提取转子位置。PMSM在αβ坐标系下的电压方程vα R*iα L*d(iα)/dt eα vβ R*iβ L*d(iβ)/dt eβ其中eα和eβ是反电动势等于-ωψfsin(θ)和ωψfcos(θ)。滑模观测器构造一个电流观测器d(iα_hat)/dt (vα - R*iα_hat - zα) / L d(iβ_hat)/dt (vβ - R*iβ_hat - zβ) / Lzα和zβ是滑模控制项通常用饱和函数或者sigmod函数代替符号函数来抑制抖振。当观测电流和实际电流的误差收敛到零时zα和zβ就包含了反电动势的信息。对zα和zβ做低通滤波再通过反正切或者锁相环提取角度和速度。滑模观测器的参数主要是滑模增益和低通滤波截止频率。滑模增益要足够大保证滑模面可达但太大会加剧抖振。低通滤波截止频率要高于电机最高运行频率但太高了噪声大太低了相位滞后大。我一般把截止频率设在电机额定频率的2到3倍。实际调试时低速段滑模观测器效果不好因为反电动势太小。这时候可以切到高频注入或者用I/F启动强拖到一定转速再切滑模。切换时要保证角度平滑否则电机会抖一下。我的做法是在切换前让滑模观测器的角度跟踪上强拖角度用一个渐变系数把角度从强拖值过渡到观测值过渡时间大概100ms。4.4 电流采样校准与偏置补偿电流采样电路存在零点偏置运放的输入失调电压、ADC的零点误差都会导致零电流时采样值不为零。这个偏置必须在启动时校准否则会直接影响FOC的控制精度。校准方法在电机不转、PWM输出关闭的情况下采多次电流值取平均作为偏置。一般采100到1000次平均后精度就够了。校准后的偏置存在变量里每次采样后减去偏置再参与计算。但偏置会随温度漂移运放的失调电压温漂一般在几μV/°C放大30倍后就是几十μV/°C对应到电流就是几mA/°C。对于精度要求高的场合得做在线偏置补偿。方法是在电机运行过程中利用PWM的零矢量时间段采样电流这时候相电流为零采到的就是偏置。但零矢量时间很短ADC采样需要时间所以得用高速ADC或者用采样保持电路。我一般会在启动时做一次偏置校准运行过程中如果发现电流波形有直流分量再手动触发一次校准。对于大多数应用一次校准就够了温漂的影响在可接受范围内。5. 常见问题与排查技巧实录5.1 电机启动困难或失步这是无感FOC最常见的问题。现象是电机启动时抖动、嗡嗡响或者干脆不转。排查思路先确认启动参数是否合理。I/F启动的电流给定不能太小否则拖不动负载也不能太大否则电机会过流保护。一般从额定电流的20%开始试慢慢加。加速时间也要合适太短了电机跟不上太长了启动慢。我一般设加速时间0.5到2秒看负载惯量。如果启动参数没问题检查观测器切换点。切换太早反电动势还没起来观测器估计的角度不准一切换就失步。切换太晚强拖阶段浪费太多时间。我一般把切换点设在额定转速的5%到10%具体看电机的最低稳定转速。还有一个容易忽略的点启动时的初始角度。无感FOC不知道转子初始位置如果随便设一个角度电机可能反转或者抖动。常用的方法是先给一个固定的电压矢量把转子拉到已知位置再开始启动。这个预定位时间大概100到500ms电压幅值取额定电压的10%到20%。5.2 电流波形畸变或转矩脉动大电流波形畸变通常有几个原因死区补偿不当、电流采样不准、PI参数不合适。死区补偿的问题前面说过过零附近补偿方向跳变会导致波形畸变。解决办法是在过零附近不补偿或者用滞环比较器。我一般设一个阈值电流绝对值小于阈值时补偿量线性衰减到零。电流采样不准可能是偏置没校准或者采样时机不对。用示波器看采样电阻上的电压波形如果和实际电流对不上就是采样电路的问题。检查运放电路、ADC参考电压、采样时机。PI参数不合适会导致电流振荡或者响应慢。如果电流波形有高频振荡说明Kp太大如果有低频振荡说明Ki太大。用阶跃响应来调先调Kp再调Ki。转矩脉动还可能是SVPWM的问题。检查扇区判断是否正确作用时间是否溢出。如果作用时间超过PWM周期说明电压指令超出了逆变器的输出能力需要限幅。5.3 高速运行时观测器失效滑模观测器在高速时可能失效原因是反电动势频率太高低通滤波器的相位滞后太大导致角度估计偏差。解决办法提高低通滤波截止频率或者用锁相环代替反正切来提取角度。锁相环对相位滞后不敏感而且能输出平滑的速度信号。我一般用锁相环带宽设在电机最高频率的5到10倍。另一个原因是高速时电流环带宽不够电流跟不上指令导致电压指令和实际电压偏差大。这时候要检查电流环的PI参数适当提高带宽。但带宽受PWM频率限制不能超过PWM频率的1/10。如果电机要跑很高的转速比如上万转可以考虑用磁编码器做有感FOC省去观测器的麻烦。磁编码器精度够成本也不高高速性能比无感好很多。5.4 常见问题速查表问题现象可能原因排查方法解决措施电机不转PWM没输出示波器看驱动信号检查定时器配置和使能电机抖动角度估计错误对比编码器和观测器角度校准观测器参数或切有感电流过大PI参数过大看电流波形是否振荡减小Kp和Ki启动失步启动电流太小加大启动电流调整I/F启动参数高速失效观测器带宽不够看高速时角度误差提高滤波截止频率转矩脉动死区补偿不当看电流过零波形调整死区补偿策略采样噪声大采样时机不对看采样时刻PWM状态改到PWM中点采样温升过高开关损耗大测MOSFET温度降低PWM频率或换低Qg管6. 调试工具与实战经验分享6.1 示波器和电流探头的使用技巧调试FOC示波器是必不可少的。看电流波形、PWM波形、角度信号都靠它。电流测量有两种方式电流探头和采样电阻。电流探头方便不用改电路但精度一般而且贵。采样电阻便宜精度高但需要隔离或者差分探头。我一般用采样电阻加差分探头看相电流的细节。看电流波形时要注意探头的带宽和采样率。FOC的电流是PWM斩波的频率20kHz电流纹波频率也是20kHz探头带宽至少得100MHz才能看清细节。采样率要足够高否则会混叠。看角度信号时可以用DAC输出观测器估计的角度和编码器的角度对比。STM32有内置DAC或者用PWM加RC滤波也能当DAC用。对比两个角度就能看出观测器的精度和相位滞后。6.2 上位机调参工具的设计FOC的参数很多PI参数、观测器参数、启动参数如果每次都在代码里改效率太低。我一般会做一个上位机工具通过串口或者CAN和MCU通信实时修改参数和查看波形。上位机用Python或者C#写都行Python的matplotlib可以实时画波形很方便。通信协议用简单的自定义协议比如帧头命令数据校验。MCU端用DMA接收不占用CPU时间。调参时先调电流环再调速度环最后调观测器。电流环调好了电流波形干净没有振荡。速度环调好了速度响应快没有超调。观测器调好了角度估计准切换平滑。我习惯把调好的参数存在Flash里下次上电自动加载。这样不用每次重新调省事。6.3 从方波驱动升级到FOC的注意事项如果你之前用的是六步换向方波驱动升级到FOC时要注意几点。硬件上方波驱动只需要三路PWMFOC需要六路PWM而且要有死区。电流采样电路也要加方波驱动一般不做电流采样。位置传感器如果原来用的是霍尔FOC可以用但要做角度插值否则精度不够。软件上方波驱动的代码很简单就是按顺序切换MOS管。FOC的代码复杂得多坐标变换、PI调节、SVPWM每一块都要仔细调。建议先用有感FOC把整个流程跑通再加无感观测器。有感FOC稳定了无感才有基础。性能上FOC比方波驱动的噪音小、效率高、低速平稳。但FOC的算力要求高方波驱动用8位机都能跑FOC至少得用M3核以上的MCU。成本上FOC的硬件成本高一些但差距在缩小现在很多国产MCU几块钱就能跑FOC。我个人在实际操作中的体会是FOC最难的不是算法本身而是调试。算法书上都有但实际电机的参数、采样电路的误差、逆变器的非线性这些才是真正花时间的地方。我调第一套FOC花了两个月大部分时间都在解决采样噪声和死区补偿的问题。后来有了经验新项目一周就能跑起来。所以如果你刚开始搞FOC不要急慢慢调每个问题搞清楚了后面就快了。最后再分享一个小技巧调试时把电流环的给定做成阶跃信号用示波器看电流响应。上升时间、超调量、稳态误差这三个指标能告诉你PI参数调得好不好。上升时间太长就加Kp超调太大就减Kp或者加Ki稳态误差大就加Ki。反复几次就能找到合适的参数。这个方法比看波形瞎调快得多。