电机驱动开发学习15. Clark、Park、反Park坐标变换

电机驱动开发学习15. Clark、Park、反Park坐标变换

    • [一、 FOC 核心坐标系概览](#一、 FOC 核心坐标系概览)
    • [二、 Clark 变换:三相静止 → \rightarrow → 两相静止( a b c → α β abc \rightarrow \alpha\beta abc→αβ)](#二、 Clark 变换:三相静止 → \rightarrow → 两相静止( a b c → α β abc \rightarrow \alpha\beta abc→αβ))
      • [1. 几何推导与等幅值约束](#1. 几何推导与等幅值约束)
    • [三、 Park 变换:两相静止 → \rightarrow → 两相旋转( α β → d q \alpha\beta \rightarrow dq αβ→dq)](#三、 Park 变换:两相静止 → \rightarrow → 两相旋转( α β → d q \alpha\beta \rightarrow dq αβ→dq))
      • [1. 数学推导](#1. 数学推导)
    • [四、 反 Park 变换:两相旋转 → \rightarrow → 两相静止( d q → α β dq \rightarrow \alpha\beta dq→αβ)](#四、 反 Park 变换:两相旋转 → \rightarrow → 两相静止( d q → α β dq \rightarrow \alpha\beta dq→αβ))
    • [五、Python 代码仿真](#五、Python 代码仿真)
        • [(1) 时域解耦(波形对比):](#(1) 时域解耦(波形对比):)
        • [(2) 空间等效(矢量圆轨迹):](#(2) 空间等效(矢量圆轨迹):)
        • [(3) 滑块交互交互调试体验:](#(3) 滑块交互交互调试体验:)
    • [六、基于 STM32F407 的工程代码实现](#六、基于 STM32F407 的工程代码实现)
      • [1. Clark 变换代码落地](#1. Clark 变换代码落地)
      • [2. Park 与反 Park 变换代码落地](#2. Park 与反 Park 变换代码落地)
    • [七、 本章总结](#七、 本章总结)

📌 前言

在上一章中,我们理解了 FOC 的核心本质------将交流无刷电机等效为直流电机控制。要实现这一步,核心秘诀就在于坐标变换

本章将用最通俗的物理直觉 + 严谨的工程推导,一起攻克 Clark 与 Park 变换,并直接给出基于野火骄阳 F407(带有硬件浮点运算单元 FPU)的高效 C 语言实现代码。


一、 FOC 核心坐标系概览

在编写代码前,我们需要建立三个坐标系的清晰图像。它们如同三层不同的"观察视角":

  1. A − B − C A-B-C A−B−C 三相静止坐标系
  • 观察者:站在电机外面不动的你。
  • 特点 :三个轴互差 120°,轴上的电流 I A , I B , I C I_A, I_B, I_C IA,IB,IC 都是随时间变化的交变正弦波。
  1. α − β \alpha - \beta α−β 两相静止坐标系
  • 观察者:依然是站在电机外面不动的你。
  • 特点 :两个轴互相垂直(90°),电流 I α , I β I_\alpha, I_\beta Iα,Iβ 虽然解耦,但依然是正弦交流电。
  1. d − q d - q d−q 两相旋转坐标系
  • 观察者:坐在转子永磁体上、跟着电机一起高速旋转的"缩小的你"。
  • 特点 : d d d 轴(直轴)始终对准转子磁场方向, q q q 轴(交轴)始终垂直于磁场方向。在你的视角里, I d I_d Id 和 I q I_q Iq 变成了静止不动的直流电

二、 Clark 变换:三相静止 → \rightarrow → 两相静止( a b c → α β abc \rightarrow \alpha\beta abc→αβ)

1. 几何推导与等幅值约束

我们希望用互相垂直的 α \alpha α 轴和 β \beta β 轴来等效代替互差 120° 的 A 、 B 、 C A、B、C A、B、C 三轴。通常,我们让 α \alpha α 轴与 A A A 轴完全重合, β \beta β 轴超前 α \alpha α 轴 90°。

根据向量投影,我们可以得到 α \alpha α 和 β \beta β 轴上的分量:

I α = I A − I B ⋅ cos ⁡ ( 60 ∘ ) − I C ⋅ cos ⁡ ( 60 ∘ ) = I A − 1 2 I B − 1 2 I C I_\alpha = I_A - I_B \cdot \cos(60^\circ) - I_C \cdot \cos(60^\circ) = I_A - \frac{1}{2}I_B - \frac{1}{2}I_C Iα=IA−IB⋅cos(60∘)−IC⋅cos(60∘)=IA−21IB−21IC

I β = 0 + I B ⋅ sin ⁡ ( 60 ∘ ) − I C ⋅ sin ⁡ ( 60 ∘ ) = 3 2 I B − 3 2 I C I_\beta = 0 + I_B \cdot \sin(60^\circ) - I_C \cdot \sin(60^\circ) = \frac{\sqrt{3}}{2}I_B - \frac{\sqrt{3}}{2}I_C Iβ=0+IB⋅sin(60∘)−IC⋅sin(60∘)=23 IB−23 IC

在实际工程中,为了保证变换前后的电流幅值大小不变 (即等幅值变换),根据基尔霍夫电流定律,在三相平衡系统中满足 I A + I B + I C = 0 I_A + I_B + I_C = 0 IA+IB+IC=0(即 I B + I C = − I A I_B + I_C = -I_A IB+IC=−IA)。

代入上式进行化简,乘以等幅值系数 2 3 \frac{2}{3} 32 后,最终的 Clark 变换公式 极为精简:

I α = I A I_\alpha = I_A Iα=IA

I β = 3 3 ( I A + 2 I B ) 或 I β = 1 3 ( I B − I C ) I_\beta = \frac{\sqrt{3}}{3}(I_A + 2I_B) \quad \text{或} \quad I_\beta = \frac{1}{\sqrt{3}}(I_B - I_C) Iβ=33 (IA+2IB)或Iβ=3 1(IB−IC)

🛠️ 工程提示 :在写 C 代码时,由于三相下桥臂电阻采样更习惯拿到 I A , I B I_A, I_B IA,IB,我们通常使用包含 I A , I B I_A, I_B IA,IB 的变形公式,避免引入 I C I_C IC,从而减少运算量。


三、 Park 变换:两相静止 → \rightarrow → 两相旋转( α β → d q \alpha\beta \rightarrow dq αβ→dq)

1. 数学推导

现在我们要把视角切换到旋转的转子上。已知转子当前的电角度为 θ \theta θ(即 d d d 轴与 α \alpha α 轴的夹角)。

将静止的 I α I_\alpha Iα 和 I β I_\beta Iβ 投影到旋转的 d d d 轴和 q q q 轴上:

I d = I α ⋅ cos ⁡ θ + I β ⋅ sin ⁡ θ I_d = I_\alpha \cdot \cos\theta + I_\beta \cdot \sin\theta Id=Iα⋅cosθ+Iβ⋅sinθ

I q = − I α ⋅ sin ⁡ θ + I β ⋅ cos ⁡ θ I_q = -I_\alpha \cdot \sin\theta + I_\beta \cdot \cos\theta Iq=−Iα⋅sinθ+Iβ⋅cosθ

  • 物理直觉 :通过引入 θ \theta θ,我们将旋转运动的物理量投射到了相对静止的参考系。此时算出来的 I d I_d Id 和 I q I_q Iq 在稳态下就是两个平稳的直流值

四、 反 Park 变换:两相旋转 → \rightarrow → 两相静止( d q → α β dq \rightarrow \alpha\beta dq→αβ)

经过电流环 PI 调节器后,我们得到了 V d V_d Vd 和 V q V_q Vq(直流电压指令)。但是,SVPWM 模块需要的是静止坐标系下的电压来产生物理 PWM。所以,我们需要执行 Park 的逆运算:

V α = V d ⋅ cos ⁡ θ − V q ⋅ sin ⁡ θ V_\alpha = V_d \cdot \cos\theta - V_q \cdot \sin\theta Vα=Vd⋅cosθ−Vq⋅sinθ

V β = V d ⋅ sin ⁡ θ + V q ⋅ cos ⁡ θ V_\beta = V_d \cdot \sin\theta + V_q \cdot \cos\theta Vβ=Vd⋅sinθ+Vq⋅cosθ

⚠️ 避坑指南 :注意看清正负号!反 Park 变换中 V α V_\alpha Vα 的公式中间是减号( − - −) ,而 V β V_\beta Vβ 中间是加号( + + +)

三个变化总结示意图:


五、Python 代码仿真

为了让复杂的矩阵投影更形象展示出来,下面使用Python的matplotlib库编写一个FOC交互式FOCus坐标变换仿真器。该仿真器支持通过滑块实时调节电机转速与电流幅值,用来同步观测空间矢量和时域波形。

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.widgets import Slider

# --- 初始常数 ---
init_Amp = 1.0  # 初始幅值
init_Freq = 0.5  # 初始频率 (降低到0.5Hz,方便肉眼观察)
FPS = 50  # 帧率
sqrt3_3 = 0.577350269  # 1/sqrt(3)

# --- 创建画布 ---
# 增加画布尺寸以容纳下方的波形图和滑块
fig = plt.figure(figsize=(14, 9))
fig.canvas.manager.set_window_title('FOC Clark Transformation Interactive Simulator')

# 划分网格布局 (3行2列)
# Top row: 矢量圆图
ax_abc_vector = plt.subplot2grid((3, 2), (0, 0), rowspan=2)
ax_ab_vector = plt.subplot2grid((3, 2), (0, 1), rowspan=2)
# Bottom row: 时间波形图
ax_abc_wave = plt.subplot2grid((3, 2), (2, 0))
ax_ab_wave = plt.subplot2grid((3, 2), (2, 1))

# 调整整体布局给滑块留出底部空间
plt.subplots_adjust(bottom=0.18, hspace=0.4, wspace=0.25)

# --- 1. 左上:ABC 空间矢量图 ---
ax_abc_vector.set_title("1. ABC Stationary Frame (Vector)", fontsize=11, fontweight='bold')
ax_abc_vector.set_xlim(-1.5, 1.5)
ax_abc_vector.set_ylim(-1.5, 1.5)
ax_abc_vector.set_aspect('equal')
ax_abc_vector.grid(True, linestyle='--', alpha=0.5)
# 绘制ABC三相物理轴线 (互差120度)
ax_abc_vector.quiver(0, 0, 1.3, 0, angles='xy', scale_units='xy', scale=1, color='gray', alpha=0.5)
ax_abc_vector.text(1.35, 0, 'A-axis', color='gray')
ax_abc_vector.quiver(0, 0, 1.3 * np.cos(2 * np.pi / 3), 1.3 * np.sin(2 * np.pi / 3), angles='xy', scale_units='xy',
                     scale=1, color='gray', alpha=0.5)
ax_abc_vector.text(1.35 * np.cos(2 * np.pi / 3), 1.3 * np.sin(2 * np.pi / 3), 'B-axis', color='gray')
ax_abc_vector.quiver(0, 0, 1.3 * np.cos(4 * np.pi / 3), 1.3 * np.sin(4 * np.pi / 3), angles='xy', scale_units='xy',
                     scale=1, color='gray', alpha=0.5)
ax_abc_vector.text(1.35 * np.cos(4 * np.pi / 3), 1.3 * np.sin(4 * np.pi / 3), 'C-axis', color='gray')

vector_abc = ax_abc_vector.quiver(0, 0, 0, 0, angles='xy', scale_units='xy', scale=1, color='purple', width=0.015,
                                  label=r'$\vec{I}_{abc}$')
trace_abc, = ax_abc_vector.plot([], [], 'purple', linestyle=':', alpha=0.6, linewidth=1.5)
ax_abc_vector.legend(loc='upper right')

# --- 2. 右上:alpha-beta 空间矢量图 ---
ax_ab_vector.set_title(r"2. $\alpha\beta$ Stationary Frame (Vector)", fontsize=11, fontweight='bold')
ax_ab_vector.set_xlim(-1.5, 1.5)
ax_ab_vector.set_ylim(-1.5, 1.5)
ax_ab_vector.set_aspect('equal')
ax_ab_vector.grid(True, linestyle='--', alpha=0.5)
ax_ab_vector.axhline(0, color='gray', alpha=0.5)
ax_ab_vector.axvline(0, color='gray', alpha=0.5)
ax_ab_vector.text(1.3, 0.05, r'$\alpha$-axis', color='gray')
ax_ab_vector.text(0.05, 1.3, r'$\beta$-axis', color='gray')

vector_ab = ax_ab_vector.quiver(0, 0, 0, 0, angles='xy', scale_units='xy', scale=1, color='darkorange', width=0.015,
                                label=r'$\vec{I}_{\alpha\beta}$')
trace_ab, = ax_ab_vector.plot([], [], 'darkorange', linestyle=':', alpha=0.6, linewidth=1.5)
ax_ab_vector.legend(loc='upper right')

# --- 3. 左下:ABC 三相电流时间波形 ---
ax_abc_wave.set_title("3. ABC Phase Currents (Time Domain)", fontsize=10)
ax_abc_wave.set_xlim(0, 4.0)  # 显示4秒的历史波形
ax_abc_wave.set_ylim(-1.5, 1.5)
ax_abc_wave.grid(True, linestyle='--', alpha=0.5)
ax_abc_wave.set_ylabel("Current (A)")
wave_Ia, = ax_abc_wave.plot([], [], 'r-', label=r'$I_A$')
wave_Ib, = ax_abc_wave.plot([], [], 'g-', label=r'$I_B$')
wave_Ic, = ax_abc_wave.plot([], [], 'b-', label=r'$I_C$')
ax_abc_wave.legend(loc='upper right', fontsize='small')

# --- 4. 右下:alpha-beta 电流时间波形 ---
ax_ab_wave.set_title(r"4. $\alpha\beta$ Currents (Time Domain)", fontsize=10)
ax_ab_wave.set_xlim(0, 4.0)
ax_ab_wave.set_ylim(-1.5, 1.5)
ax_ab_wave.grid(True, linestyle='--', alpha=0.5)
wave_Ialpha, = ax_ab_wave.plot([], [], 'r-', label=r'$I_\alpha$')
wave_Ibeta, = ax_ab_wave.plot([], [], 'b-', label=r'$I/\beta$')
ax_ab_wave.legend(loc='upper right', fontsize='small')

# --- 添加交互滑块 (Sliders) ---
ax_slider_freq = plt.axes([0.15, 0.08, 0.7, 0.03])
ax_slider_amp = plt.axes([0.15, 0.03, 0.7, 0.03])

slider_freq = Slider(ax_slider_freq, 'Speed (Freq Hz)', 0.0, 3.0, valinit=init_Freq, valfmt='%1.2f Hz')
slider_amp = Slider(ax_slider_amp, 'Current Amp (A)', 0.1, 1.5, valinit=init_Amp, valfmt='%1.2f A')

# --- 动态数据追踪变量 ---
time_history = []
Ia_history, Ib_history, Ic_history = [], [], []
# 修复:左边两个变量,右边对应两个空列表
Ialpha_history, Ibeta_history = [], []
trace_x_abc, trace_y_abc = [], []
trace_x_ab, trace_y_ab = [], []

current_theta = 0.0  # 积分累计电角度,防止改频率时波形跳变
t_global = 0.0  # 全局时间计数


# --- 动画更新核心函数 ---
def update(frame):
    global current_theta, t_global

    # 获取滑块当前实时值
    freq = slider_freq.val
    amp = slider_amp.val

    # 计算步进时间
    dt = 1.0 / FPS
    t_global += dt
    # 根据当前频率累加角度: d_theta = 2 * pi * f * dt
    current_theta += 2 * np.pi * freq * dt

    # 1. 计算三相平衡交流电指令
    Ia = amp * np.cos(current_theta)
    Ib = amp * np.cos(current_theta - 2 * np.pi / 3)
    Ic = amp * np.cos(current_theta + 2 * np.pi / 3)

    # 2. 执行等幅值 Clark 变换
    Ialpha = Ia
    Ibeta = (Ia + 2.0 * Ib) * sqrt3_3

    # 3. 物理空间合成矢量(ABC)
    res_abc_x = Ia + Ib * np.cos(2 * np.pi / 3) + Ic * np.cos(4 * np.pi / 3)
    res_abc_y = 0 + Ib * np.sin(2 * np.pi / 3) + Ic * np.sin(4 * np.pi / 3)

    # 4. 缓存历史数据用于波形绘制 (限制最多保存200点,防止内存溢出)
    time_history.append(t_global)
    Ia_history.append(Ia)
    Ib_history.append(Ib)
    Ic_history.append(Ic)
    Ialpha_history.append(Ialpha)
    Ibeta_history.append(Ibeta)

    if len(time_history) > 200:
        time_history.pop(0)
        Ia_history.pop(0)
        Ib_history.pop(0)
        Ic_history.pop(0)
        Ialpha_history.pop(0)
        Ibeta_history.pop(0)

    # 5. 缓存矢量旋转轨迹
    trace_x_abc.append(res_abc_x)
    trace_y_abc.append(res_abc_y)
    trace_x_ab.append(Ialpha)
    trace_y_ab.append(Ibeta)
    if len(trace_x_abc) > 40:  # 轨迹只保留最近40帧
        trace_x_abc.pop(0);
        trace_y_abc.pop(0)
        trace_x_ab.pop(0);
        trace_y_ab.pop(0)

    # --- 刷新图形元素 ---
    # 更新上方矢量箭头
    vector_abc.set_UVC(res_abc_x, res_abc_y)
    vector_ab.set_UVC(Ialpha, Ibeta)

    # 更新上方矢量圆圈轨迹
    trace_abc.set_data(trace_x_abc, trace_y_abc)
    trace_ab.set_data(trace_x_ab, trace_y_ab)

    # 更新下方波形图数据
    wave_Ia.set_data(time_history, Ia_history)
    wave_Ib.set_data(time_history, Ib_history)
    wave_Ic.set_data(time_history, Ic_history)
    wave_Ialpha.set_data(time_history, Ialpha_history)
    wave_Ibeta.set_data(time_history, Ibeta_history)

    # 动态调整下方波形图的时间轴 X 轴视窗
    if t_global > 4.0:
        ax_abc_wave.set_xlim(t_global - 4.0, t_global)
        ax_ab_wave.set_xlim(t_global - 4.0, t_global)
    else:
        ax_abc_wave.set_xlim(0, 4.0)
        ax_ab_wave.set_xlim(0, 4.0)

    return (vector_abc, vector_ab, trace_abc, trace_ab,
            wave_Ia, wave_Ib, wave_Ic, wave_Ialpha, wave_Ibeta)


# --- 启动动画 ---
ani = FuncAnimation(fig, update, frames=None, blit=False, interval=1000 / FPS, cache_frame_data=False)

plt.show()

运行该 Python 脚本后,我们可以通过交互界面直观地印证 Clark 变换的几个核心硬核结论:

(1) 时域解耦(波形对比):
  • 观察左下角【图3】:三相平衡电流 I A , I B , I C I_A, I_B, I_C IA,IB,IC 彼此在时间轴上互差 120 ∘ 120^\circ 120∘ 电角度,幅值均为滑块设定的 A m p Amp Amp。
  • 观察右下角【图4】:经 Clark 变换后,输出的 I α I_\alpha Iα 与基准 I A I_A IA 曲线完全重合(这完美契合了数学推导中 I α = I A I_\alpha = I_A Iα=IA 的简便公式)。而 I β I_\beta Iβ 则蜕变成了一个在相位上精准超前 I α I_\alpha Iα 恰好 90 ∘ 90^\circ 90∘ 的标准正弦波。
  • 结论:Clark 变换成功将三路非正交的 120 ∘ 120^\circ 120∘ 交流量,解耦为了两路空间正交(互差 90 ∘ 90^\circ 90∘)的直角坐标系交流量。
(2) 空间等效(矢量圆轨迹):
  • 观察左上【图1】(紫色箭头 I ⃗ a b c \vec{I}{abc} I abc)与右上【图2】(橘色箭头 I ⃗ α β \vec{I}{\alpha\beta} I αβ):随着时间推移,两边的空间合成矢量都在各自的坐标系中顺时针做匀速圆周旋转。
  • 细心对比可以发现,无论是旋转的角度(相位),还是旋转轨迹圆的半径(幅值),两边都完全一模一样!
  • 物理本质:这通过图形化铁证证明了等幅值约束 Clark 变换的真谛------变换不仅没有改变合成磁场的旋转特性,而且保持了"在数值上变换前后的电流幅值完全相等",这对后续我们在 MCU 内部设定电流采样限制(如保护阈值)和调试 PI 控制器提供了极大便利!
(3) 滑块交互交互调试体验:

尝试将底部的 Speed 滑块拖动至 0.00 Hz:电机瞬间静止,此时下方的时域正弦波停止向右滚动。你可以清晰看到:当物理 A 轴电流( I A I_A IA)达到正向最大值时,B、C 两相电流正好处于负的 1 2 \frac{1}{2} 21 倍幅值处,它们在空间上共同合成了方向直指 α \alpha α 轴正方向的旋转矢量。

有了这两路完美的、互差 90 ∘ 90^\circ 90∘ 的静止直角交流电 I α , I β I_\alpha, I_\beta Iα,Iβ 后,我们已经成功解决了线圈在空间上的不便利性。现在,最关键的挑战来了:虽然空间解耦了,但这两个物理量依旧是随时间高频变化的正弦交流电,PI 控制器对交流电的跟踪效果很差。为了解决这个问题,我们需要进入下一级视角------坐上高速旋转的转子,用 Park 变换 将其"驯服"为直流电!


六、基于 STM32F407 的工程代码实现

野火骄阳 F407 搭载了 Cortex-M4 核心,支持硬件浮点数运算(FPU)。为了追求极致的执行效率,我们在编写 FOC 算法时,应尽量使用 float 类型,并调用标准的 arm_math.h 库或高效的硬件三角函数。

这里我们定义一个 FOC 的核心结构体,用于统一管理变量:

c 复制代码
typedef struct {
    // 输入的三相电流
    float Ia;
    float Ib;
    float Ic;
    
    // Clark 变换输出
    float Ialpha;
    float Ibeta;
    
    // Park 变换输出
    float Id;
    float Iq;
    
    // 电流环 PI 输入的参考目标值
    float Id_ref;
    float Iq_ref;
    
    // 电流环 PI 输出的电压指令
    float Vd;
    float Vq;
    
    // 反 Park 变换输出
    float Valpha;
    float Vbeta;
    
    // 当前转子电角度(弧度制: 0 ~ 2*PI)
    float theta;
    float sin_theta;
    float cos_theta;
} FOC_Ctrl_t;

FOC_Ctrl_t g_foc_ctrl; // 全局 FOC 控制结构体

1. Clark 变换代码落地

c 复制代码
#define SQRT3_3   0.577350269f  // 1/sqrt(3) 的预计算常数,避免在中断中做除法

/**
  * @brief  克拉克变换 (Clark Transformation)
  * @param  foc: FOC控制结构体指针
  * @note   输入: foc->Ia, foc->Ib  输出: foc->Ialpha, foc->Ibeta
  */
void FOC_Clark(FOC_Ctrl_t *foc)
{
    // 等幅值 Clark 变换简化公式
    foc->Ialpha = foc->Ia;
    foc->Ibeta  = (foc->Ia + 2.0f * foc->Ib) * SQRT3_3;
}

2. Park 与反 Park 变换代码落地

c 复制代码
#include "arm_math.h" // 调用库函数计算正余弦

/**
  * @brief  帕克变换 (Park Transformation)
  */
void FOC_Park(FOC_Ctrl_t *foc)
{
    // 提前计算好当前角度的正余弦值(也可使用查表法优化)
    foc->sin_theta = arm_sin_f32(foc->theta);
    foc->cos_theta = arm_cos_f32(foc->theta);
    
    // 核心公式映射
    foc->Id =  foc->Ialpha * foc->cos_theta + foc->Ibeta * foc->sin_theta;
    foc->Iq = -foc->Ialpha * foc->sin_theta + foc->Ibeta * foc->cos_theta;
}

/**
  * @brief  反帕克变换 (Inverse Park Transformation)
  */
void FOC_InvPark(FOC_Ctrl_t *foc)
{
    // 注意中间的正负号,别和 Park 变换搞混了
    foc->Valpha = foc->Vd * foc->cos_theta - foc->Vq * foc->sin_theta;
    foc->Vbeta  = foc->Vd * foc->sin_theta + foc->Vq * foc->cos_theta;
}

七、 本章总结

  1. Clark 变换 完成了线圈空间的精简( 3 3 3 轴变 2 2 2 轴),它不需要角度参与,只负责空间解耦。
  2. Park 变换 完成了物理视角的跨越(静止变旋转),必须传入精准的转子电角度 θ \theta θ,负责把交流电提炼为直流电。
  3. 反 Park 变换 是控制输出的桥梁,负责将 PI 调节器算出的 V d , V q V_d, V_q Vd,Vq 直流指令还原回控制定子的 V α , V β V_\alpha, V_\beta Vα,Vβ 交流电压。

三大变换在每个 PWM 周期(通常为 50 μ s 50\mu s 50μs 或 100 μ s 100\mu s 100μs)的定时器中断里会被高频调用,因此在代码中严禁使用动态除法 ,所有根号运算必须提前定义为常数(如 SQRT3_3),以腾出 CPU 耗时给后面的观测器算法。

下一章,我们将正式接入 PID 控制器,把本章解耦出来的 I d I_d Id 和 I q I_q Iq 锁死在闭环中,实现 第16章:DQ双轴电流环闭环控制


本系列教程学习资源来自野火官方电机教程,部分代码及博客内容摘自官方教程。

本系列教程使用野火骄阳 F407 开发板及野火有刷/无刷驱动板。

适配场景:家电工业级FOC双闭环方案变频开发