06FOC 总体流程

采样、变换、电流环、SVPWM 闭环链路

本模块主旨
FOC = 每个 PWM 周期跑一遍的 7 段纯函数流水线;时序预算 + 解析整定 + 解耦前馈三件事不掉链,电机调试就只剩选参数。

学完应能回答

查看完整 Walkthrough(8 步 + 4 误区)

总览
FOC 不是数学难,是工程链路长。把每段都看成一个可独立验证的纯函数,整个系统才稳。

零基础速入

类比
FOC 就像给三相交流电机装了一台"翻译机"。普通办法直接调三相电压,电机看到的是不停旋转的复杂波形,没法精确控转矩。FOC 把复杂的三相变成两个稳定的直流量(Id 控磁链、Iq 控转矩),就像把摇晃的船舱地板换成静止的——你站在静止的地板上调阀门容易得多。
核心概念
FOC 不是某个单一公式,而是一条**每个 PWM 周期跑一遍**的流水线:采样 → Clarke → Park → 电流 PI → 反 Park → SVPWM → 输出。每个环节只做一件事,错了能定位。

为什么要学

第一手操作
点击顶部"电流环响应"标签,把右边 Iq 阶跃指令拖到 5A,看 Iq(绿)追指令(虚线)的过程。然后把"角度误差 Δθ"从 0 拖到 15°,看 Iq 阶跃时 Id(蓝)也被拉起来——这就是著名的"dq 串扰"。

学习目标

核心概念

公式

FOC 流水线
abc → Clarke → Park → PI(Id, Iq) → inv-Park → SVPWM → 桥臂

每一段都是纯函数,输入输出明确,便于移植到 C / STM32 / MATLAB。

dq PMSM 模型
vd = R·id + Ld·did/dt - ω·Lq·iq; vq = R·iq + Lq·diq/dt + ω·(Ld·id + ψf)

dq 之间存在交叉耦合项 ω·L·iq 和 ω·L·id;速度越高耦合越强,需要在 PI 输出加解耦前馈。

电流环典型整定
Kp = ω_bw × L, Ki = ω_bw × R

想要 1 kHz 带宽,Kp = 6283 × 0.0012 ≈ 7.5(实际 PWM 16k 时取 1-3 较稳)。Ki/Kp = R/L 让零点抵消极点。

工程意义

STM32 移植指南

常见误区

  • 在 UI 或业务层写控制算法,无法移植和单元测试。
  • 中断里加 printf / HAL_Delay / 浮点除法,PWM 周期超时。
  • 采样点选在 PWM 边沿附近(噪声大)。
  • PI 没做抗积分饱和,输出撞限幅后释放出大超调。
  • 没在中断尾部用 __DSB() 确保 CCR 写入生效。

调试方法

建议实验

STM32 C 代码骨架

/* ============================================
 * foc.c — FOC 中断主循环(运行在 PWM 16kHz ISR 内)
 * 适配 STM32G4 (Cortex-M4F + FPU),单次执行 < 6 μs
 * ============================================ */
#include "foc.h"

static pi_state_t g_pi_d = { .integral = 0 };
static pi_state_t g_pi_q = { .integral = 0 };

void TIM1_UP_TIM16_IRQHandler(void) {
    if (TIM1->SR & TIM_SR_UIF) {
        TIM1->SR = ~TIM_SR_UIF;

        /* 1. 采样三相电流(ADC 注入序列已经触发) */
        float ia = adc_to_amps(ADC1->JDR1, g_offset.ia);
        float ib = adc_to_amps(ADC1->JDR2, g_offset.ib);
        float ic = -ia - ib;     // 三相和为零,省一路 ADC

        /* 2. 读电角度(编码器/观测器) */
        float theta_e = encoder_to_theta_e(
            ENCODER->CNT, g_param.encoder_zero, g_param.pole_pairs);
        float sin_t, cos_t;
        sincosf(theta_e, &sin_t, &cos_t);

        /* 3. Clarke:abc → αβ */
        float i_alpha = ia;
        float i_beta  = ONE_OVER_SQRT3 * (ia + 2.0f * ib);

        /* 4. Park:αβ → dq(同步旋转坐标) */
        float i_d =  cos_t * i_alpha + sin_t * i_beta;
        float i_q = -sin_t * i_alpha + cos_t * i_beta;

        /* 5. 电流 PI(在 dq 域,控直流量) */
        float v_d = pi_step(&g_pi_d, g_ref.id - i_d, g_param.kp, g_param.ki, DT);
        float v_q = pi_step(&g_pi_q, g_ref.iq - i_q, g_param.kp, g_param.ki, DT);

        /* 5b. 解耦前馈(高速时建议加,低速可省) */
        v_d -= 2.0f * M_PI * g_state.elec_freq * g_param.lq * i_q;
        v_q += 2.0f * M_PI * g_state.elec_freq * (g_param.ld * i_d + g_param.psi_f);

        /* 5c. 圆形限幅(SVPWM 线性区 ≈ Udc/√3) */
        float v_lim = g_state.udc * ONE_OVER_SQRT3 * 0.95f;
        float v_mag = sqrtf(v_d*v_d + v_q*v_q);
        if (v_mag > v_lim) { v_d *= v_lim/v_mag; v_q *= v_lim/v_mag; }

        /* 6. 反 Park:dq → αβ */
        float v_alpha = cos_t * v_d - sin_t * v_q;
        float v_beta  = sin_t * v_d + cos_t * v_q;

        /* 7. SVPWM:αβ → 三相占空比 */
        svpwm_t sv = svpwm_calc(v_alpha, v_beta, g_state.udc);

        /* 8. 写入 CCR(下一个 PWM 周期生效) */
        TIM1->CCR1 = (uint16_t)(sv.duty_a * TIM1->ARR);
        TIM1->CCR2 = (uint16_t)(sv.duty_b * TIM1->ARR);
        TIM1->CCR3 = (uint16_t)(sv.duty_c * TIM1->ARR);
        __DSB();
    }
}

下一步

随堂题

FOC 在 dq 坐标里做 PI,相比直接在 abc 做控制最大的好处是什么?
  1. 计算量少
  2. 稳态时控制对象是直流量,PI 可以严格消除稳态误差 (正确)
  3. 不需要传感器
  4. 硬件成本低
提示:abc 三相是 AC 量,标准 PI 跟踪 AC 会有稳态相位/幅值误差;dq 是 DC 量,PI 可以做到零稳态误差。
电流环 Kp 增大到使 Iq 出现 30% 超调和振荡,最可能的原因?
  1. Ki 太小
  2. 电压限幅太大
  3. Kp 已经超过电流环带宽 / 采样延迟匹配 (正确)
  4. 电机参数错
提示:电流环带宽 ω_bw ≈ Kp/L。Kp 太大让 ω_bw 高于 1/(2π·延迟),相位裕度耗尽就开始振荡。
同时给 Iq 阶跃指令但 Id 也被拉起来一个峰值,最可能的原因?
  1. Kp 不够
  2. 编码器零位没对齐 / 角度有误差 Δθ (正确)
  3. PWM 频率太低
  4. ADC 采样错
提示:Iq 投影到错误旋转的 d 轴上就会"溢"到 Id 上。试改"角度误差 Δθ"看现象。
高速运行时电流环响应变慢、有晃动,加什么能改善?
  1. 加大 Kp
  2. 加大 Ki
  3. 加 dq 解耦前馈(vd 减 ω·Lq·iq、vq 加 ω·(Ld·id + ψf)) (正确)
  4. 降低 PWM 频率
提示:高速时 ω·L 项让 d/q 互相干扰,靠 PI 反馈修复慢。前馈直接抵消这部分耦合。
FOC 中断里出现下面哪个最危险?
  1. 浮点乘加
  2. sincosf 调用
  3. printf 或 HAL_Delay (正确)
  4. CCR 写入
提示:printf/Delay 阻塞数百 μs 到 ms 级,PWM 周期 60μs 完全装不下,会立刻丢拍。

相关公式索引

FOC 总采样-生效延迟
t_delay ≈ 1.5·Ts (ADC 中点 + CCR 预装载); 电流环带宽上限 ≈ 1/(2π·1.5·Ts)