无刷电机学习笔记汇总【FOC】【SVPWM】【无刷电机控制板】
STM32G4版本的无刷电机控制板,包含霍尔,该文章主要包含了FOC算法介绍,以及MATLAB仿真学习,实际的C语言实现。
简述
日期: 2025年7月10日
Made BY: JCML
状态: 整理完善
涉及内容: FOC, MATLAB, STM32, 三相电, 硬件, 算法, 闭环控制
优先级: 修缮完成
做着个原来的初衷是想做一个平衡步兵机器人,需要使用关节电机,然后发觉市面上的带控制器的电机都非常贵,就在咸鱼淘了四个4010电机,没有电调。去年设计了一版STM32F1的版本也基本把仿真和上板调试都搞了,但在设计过程中发现STM32F103C8做这个确实有点捉襟见肘,也没有用操作系统只记得当时做的确实有点不咋好。前段时间刚好有空就想着继续完善一下。也简单记录一下自己做的工程,包含硬件和软件部分内容可能写的有点不好,还望见谅。
理论学习
几个变换
ABC三相平面静止坐标系
Clark变换的本质即使将变化的adc 三相变换到静止的α β 坐标系中,对于同一个合矢量,我们可用不用的坐标来表示。

abc三相坐标系下的矢量合成

α β 坐标系下的矢量合成
可以将三相对称正弦电流的大小表示如下,
{ I a = I m cos ( ω t ) I b = I m cos ( ω t − 2 π 3 ) I c = I m cos ( ω t + 2 π 3 ) 其中, I m 标识赋值; ω = 2 π f 标识速度,三项电流在空间上互差120°。 \left\{\begin{array}{lcl}I_a=&I_m\cos(\omega t)\\I_b=&I_m\cos(\omega t-\frac{2\pi}3)\\I_c&=&I_m\cos(\omega t+\frac{2\pi}3)\end{array}\right.\\ \text{其中,}I_m\text{ 标识赋值; }\omega=2\pi f\text{ 标识速度,三项电流在空间上互差120°。} ⎩ ⎨ ⎧Ia=Ib=IcImcos(ωt)Imcos(ωt−32π)=Imcos(ωt+32π)其中,Im 标识赋值; ω=2πf 标识速度,三项电流在空间上互差120°。
三相电流的矢量表达和合成矢量可以这样表达:
{ I a → = I a ⋅ e 0 I b → = I b ⋅ e − j 2 π 3 I c → = I c ⋅ e j 2 π 3 I s → = I a → + I b → + I c → \begin{cases}\overrightarrow{I_a}=&I_a\cdot e^0\\\overrightarrow{I_b}=&I_b\cdot e^{-j\frac{2\pi}3}\\\overrightarrow{I_c}=&I_c\cdot e^{j\frac{2\pi}3}\end{cases}\\\\ \overrightarrow{I_s}=\overrightarrow{I_a}+\overrightarrow{I_b}+\overrightarrow{I_c} ⎩ ⎨ ⎧Ia=Ib=Ic=Ia⋅e0Ib⋅e−j32πIc⋅ej32πIs=Ia+Ib+Ic
所以 I s → \overrightarrow{I_s} Is就等于
I s → = I m cos ( ω t ) + I m cos ( ω t − 2 π 3 ) ⋅ e − j 2 π 3 + I m cos ( ω t + 2 π 3 ) ⋅ e j 2 π 3 \overrightarrow{I_s}=I_m\cos(\omega t)+I_m\cos(\omega t-\frac{2\pi}3)\cdot e^{-j\frac{2\pi}3}+I_m\cos(\omega t+\frac{2\pi}3)\cdot e^{j\frac{2\pi}3} Is=Imcos(ωt)+Imcos(ωt−32π)⋅e−j32π+Imcos(ωt+32π)⋅ej32π
利用欧拉公式 e j x = cos x + j sin x \text{ }e^{jx}=\cos x+j\sin x ejx=cosx+jsinx 展开化简得到
I s → = 3 2 I m cos ( ω t ) + j 3 2 I m sin ( ω t ) \overrightarrow{I_s}=\frac32I_m\cos(\omega t)+j\frac32I_m\sin(\omega t) Is=23Imcos(ωt)+j23Imsin(ωt)
即下面的公式所示,三相对称正弦电流的合成矢量的一个角速度为 ω \omega ω 绕中心点旋转的矢量,因此能形成旋转磁场。它的幅值为单相幅值的 3 2 \frac32 23倍
I s → = 3 2 I m e − j ω t \overrightarrow{I_s}=\frac32I_me^{-j\omega t} Is=23Ime−jωt
-
Clark变换
Clark变换
三维坐标系ABC(非直角坐标系)降为二维坐标系αB(直角坐标系),这个过程称为投影(不同于图形学中的透视投影)

α 与A方向相同,将A、B、C方向上的矢量 I a , I b , I c 均投影到α、β方向上,有 I α = I a − s i m 30 ° I b − c o s 60 ° I c = I a − 1 2 I b − 1 2 I c I β = c o s 30 ° I b − s i n 60 ° I c = 3 2 I b − 3 2 I c \alpha\text{与A方向相同,将A、B、C方向上的矢量}I_a,I_b,I_c\text{均投影到α、β方向上,有}\\I_{\alpha}=I_{a}-sim30°I_{b}-cos60°I_{c}=I_{a}-\frac{1}{2}I_{b}-\frac{1}{2}I_{c}\\I_{\beta}=cos30°I_{b}-sin60°I_{c}=\frac{\sqrt{3}}{2}I_{b}-\frac{\sqrt{3}}{2}I_{c} α与A方向相同,将A、B、C方向上的矢量Ia,Ib,Ic均投影到α、β方向上,有Iα=Ia−sim30°Ib−cos60°Ic=Ia−21Ib−21IcIβ=cos30°Ib−sin60°Ic=23Ib−23Ic
将其写成矩阵形式,即可得到Clark变换的几种形式
Clark变换基本形式
[ I α I β ] = [ 1 − 1 2 − 1 2 0 3 2 − 3 2 ] [ I a I b I c ] \begin{bmatrix}I_\alpha\\I_\beta\end{bmatrix}=\begin{bmatrix}1&-\frac12&-\frac12\\0&\frac{\sqrt3}2&-\frac{\sqrt3}2\end{bmatrix}\begin{bmatrix}I_a\\I_b\\I_c\end{bmatrix} [IαIβ]=[10−2123−21−23] IaIbIc
等幅值变换形式
[ I α I β ] = 2 3 [ 1 − 1 2 − 1 2 0 3 2 − 3 2 ] [ I a I b I c ] \begin{bmatrix}I_\alpha\\I_\beta\end{bmatrix}=\frac23\begin{bmatrix}1&-\frac12&-\frac12\\0&\frac{\sqrt3}2&-\frac{\sqrt3}2\end{bmatrix}\begin{bmatrix}I_a\\I_b\\I_c\end{bmatrix} [IαIβ]=32[10−2123−21−23] IaIbIc
等功率变换形式
[ I α I β ] = 2 3 [ 1 − 1 2 − 1 2 0 3 2 − 3 2 ] [ I a I b I c ] \begin{bmatrix}I_\alpha\\I_\beta\end{bmatrix}=\sqrt{\frac23}\begin{bmatrix}1&-\frac12&-\frac12\\0&\frac{\sqrt3}2&-\frac{\sqrt3}2\end{bmatrix}\begin{bmatrix}I_a\\I_b\\I_c\end{bmatrix} [IαIβ]=32[10−2123−21−23] IaIbIc
- 等幅值变换的优势:
- 控制环路设计更直观(如PI控制器参数无需因幅值缩放而调整)。
- 在
SVPWM(空间矢量调制)中广泛使用,简化电压矢量合成。
- 等功率变换的优势:
- 能量计算、效率分析时无需额外系数补偿。
- 物理意义更严谨(符合能量守恒定律)。
此处给出两种变换形式的证明
对基本形式做变换
[ I α I β ] = k [ 1 − 1 2 − 1 2 0 3 2 − 3 2 ] [ I a I b I c ] \begin{bmatrix}I_\alpha\\I_\beta\end{bmatrix}=k\begin{bmatrix}1&-\frac{1}{2}&-\frac{1}{2}\\0&\frac{\sqrt{3}}{2}&-\frac{\sqrt{3}}{2}\end{bmatrix}\begin{bmatrix}I_a\\I_b\\I_c\end{bmatrix} [IαIβ]=k[10−2123−21−23] IaIbIc
根据基尔霍夫电流和电压定律 I a + I b + I c = 0 I_a+I_b+I_c=0 Ia+Ib+Ic=0, U a + U b + U c = 0 U_a+U_b+U_c=0 Ua+Ub+Uc=0可得
{ u α = 3 2 k U a U β = 3 2 k ( U b − U c ) , { i α = 3 2 k I a I β = 3 2 k ( I b − I c ) \begin{cases}u_\alpha=\frac32kU_a\\U_\beta=\frac{\sqrt3}2k(U_b-U_c)\end{cases},\begin{cases}i_\alpha=\frac32kI_a\\I_\beta=\frac{\sqrt3}2k(I_b-I_c)\end{cases} {uα=23kUaUβ=23k(Ub−Uc),{iα=23kIaIβ=23k(Ib−Ic)
I b − I c = − 3 I m s i n θ , U b − U c = − 3 U m s i n θ I_b-I_c=-\sqrt3I_msin\theta,U_b-U_c=-\sqrt3U_msin\theta Ib−Ic=−3Imsinθ,Ub−Uc=−3Umsinθ
-
对等幅值变换而言
I α 2 + I β 2 = 9 4 k 2 I a 2 + 3 4 k 2 ( I b − I c ) 2 = 3 4 k 2 [ 3 I a 2 + ( I b − I c ) 2 ] = 3 4 k 2 I m [ 3 c o s 2 θ + 3 s i n 2 θ ] = 9 4 k 2 I m 2 = I m 2 ⟹ k 2 = 4 9 k = ± 2 3 \begin{aligned}I_{\alpha}^{2}+I_{\beta}^{2}&=\frac94k^2I_a^2+\frac34k^2(I_b-I_c)^2\\&=\frac34k^2[3I_a^2+(I_b-I_c)^2]\\&=\frac34k^2I_m[3cos^2\theta+3sin^2\theta]\\&=\frac94k^2I_m^2=I_m^2\\\implies k^2&=\frac49\\k&=\pm\frac23\end{aligned} Iα2+Iβ2⟹k2k=49k2Ia2+43k2(Ib−Ic)2=43k2[3Ia2+(Ib−Ic)2]=43k2Im[3cos2θ+3sin2θ]=49k2Im2=Im2=94=±32
又因为 I a 和 I α I_a和I_α Ia和Iα的方向一致,故取 k = 2 3 k = \frac23 k=32
-
对功率相等而言
P a b c = U a i a + U b I b + U c I c = U m U m [ c o s 2 θ + c o s 2 ( θ + 2 π 3 ) + c o s 2 ( θ − 2 π 3 ) ] = 3 2 U m I m P α β = u α I α + U β I β = 9 4 k 2 U α I α + 3 4 k 2 U α I α + 3 4 k 2 ( U b − u c ) ( I b − I c ) = 3 4 k 2 [ 3 U m I m c o s 2 θ + ( − 3 I m s i n θ ) ( − 3 U m s i n θ ) ] = 3 4 k 2 ⋅ [ 3 U m I m ( c o s 2 θ + s i n 2 θ ) ] = 9 4 k 2 U m I m = P a b c = 3 2 V m I m ⟹ k = ± 2 3 \begin{aligned}P_{abc}&=U_{a}i_{a}+U_{b}I_{b}+U_{c}I_{c}\\&=U_{m}U_{m}[cos^{2}\theta+cos^{2}(\theta+\frac{2\pi}{3})+cos^{2}(\theta-\frac{2\pi}{3})]\\&=\frac{3}{2}U_{m}I_{m}\\&P_{\alpha\beta}=u_{\alpha}I_{\alpha}+U_{\beta}I_{\beta}\\&=\frac{9}{4}k^{2}U_{\alpha}I_{\alpha}+\frac{3}{4}k^{2}U_{\alpha}I_{\alpha}+\frac{3}{4}k^{2}(U_{b}-u_{c})(I_{b}-I_{c})\\&=\frac{3}{4}k^{2}[3U_{m}I_{m}cos^{2}\theta+(-\sqrt{3}I_{m}sin\theta)(-\sqrt{3}U_{m}sin\theta)]\\&=\frac{3}{4}k^{2}\cdot[3U_{m}I_{m}(cos^{2}\theta+sin^{2}\theta)]\\&=\frac{9}{4}k^{2}U_{m}I_{m}=P_{abc}=\frac{3}{2}V_{m}I_{m}\\\implies k=\pm\sqrt{\frac{2}{3}}\end{aligned} Pabc⟹k=±32=Uaia+UbIb+UcIc=UmUm[cos2θ+cos2(θ+32π)+cos2(θ−32π)]=23UmImPαβ=uαIα+UβIβ=49k2UαIα+43k2UαIα+43k2(Ub−uc)(Ib−Ic)=43k2[3UmImcos2θ+(−3Imsinθ)(−3Umsinθ)]=43k2⋅[3UmIm(cos2θ+sin2θ)]=49k2UmIm=Pabc=23VmIm
又因为 I a 和 I α I_a和I_α Ia和Iα的方向一致,故取 k = 2 3 k = \sqrt{\frac23} k=32
逆Clark变换
克拉克逆变换,是克拉克变换的逆过程,由二维矢量形式重新升维变回原来的三相电流波形:
( I α , I β ) → ( I a , I b , I c ) (I_\alpha,I_\beta)\to(I_a,I_b,I_c) (Iα,Iβ)→(Ia,Ib,Ic)
为简化计算,后面我们不用克拉克变换基本形式,而是用等幅值变换形式,即
{ I α = I a I β = 1 3 ( I b − I c ) = 1 3 ( 2 I b + I a ) \begin{cases}I_\alpha=I_a\\I_\beta=\frac1{\sqrt3}(I_b-I_c)=\frac1{\sqrt3}(2I_b+I_a)\end{cases} {Iα=IaIβ=31(Ib−Ic)=31(2Ib+Ia)
反求其三相电流
I a = I α I b = 3 I β − I α 2 I c = − ( I a + I b ) = − 3 I β + I α 2 \begin{aligned}&I_{a}=I_{\alpha}\\&I_{b}=\frac{\sqrt{3}I_\beta-I_\alpha}2\\&I_{c}=-(I_a+I_b)=-\frac{\sqrt{3}I_\beta+I_\alpha}2\end{aligned} Ia=IαIb=23Iβ−IαIc=−(Ia+Ib)=−23Iβ+Iα
即可得到逆Clark变换
[ I a I b I c ] = [ 1 0 − 1 2 3 2 − 1 2 − 3 2 ] [ I α I β ] \begin{bmatrix}I_a\\I_b\\I_c\end{bmatrix}=\begin{bmatrix}1&0\\-\frac12&\frac{\sqrt3}2\\-\frac12&-\frac{\sqrt3}2\end{bmatrix}\begin{bmatrix}I_\alpha\\I_\beta\end{bmatrix} IaIbIc = 1−21−21023−23 [IαIβ]
Park变换
在电机的定子线圈上建立αβ坐标系,在转子上建立dq 坐标系(均为局部坐标系),将两个局部坐标系画到一起得到下面的图示。

其中dq 坐标随着转子转动,D轴指向电机的N级。αβ坐标系跟定子保持不动,dq 坐标系因转动造成的与αβ坐标轴的差角θ,称之为电角度。于是我们可以得到两个坐标系的变换关系:
电流映射到D轴上α、β分量: I d = I α c o s θ + I β s i n θ 电流映射到Q轴上α、β分量: I q = − I α s i n θ + I β c o s θ \text{电流映射到D轴上α、β分量: }I_d=I_\alpha cos\theta+I_\beta sin\theta\\\text{电流映射到Q轴上α、β分量: }I_q=-I_\alpha sin\theta+I_\beta cos\theta 电流映射到D轴上α、β分量: Id=Iαcosθ+Iβsinθ电流映射到Q轴上α、β分量: Iq=−Iαsinθ+Iβcosθ
将其写成矩阵形式即可得到Park变换
[ I d I q ] = [ c o s θ s i n θ − s i n θ c o s θ ] [ I α I β ] \begin{bmatrix}I_d\\I_q\end{bmatrix}=\begin{bmatrix}cos\theta&sin\theta\\-sin\theta&cos\theta\end{bmatrix}\begin{bmatrix}I_\alpha\\I_\beta\end{bmatrix} [IdIq]=[cosθ−sinθsinθcosθ][IαIβ]
逆Park变换
根据旋转的逆变换特性很容易得到其逆变换特性
Park逆变换
[ I α I β ] = [ cos θ sin θ − sin θ cos θ ] − 1 [ I d I q ] \begin{bmatrix}I_\alpha\\I_\beta\end{bmatrix}=\begin{bmatrix}\cos\theta&\sin\theta\\-\sin\theta&\cos\theta\end{bmatrix}^{-1}\begin{bmatrix}I_d\\I_q\end{bmatrix} [IαIβ]=[cosθ−sinθsinθcosθ]−1[IdIq]
I a = I d cos θ − I q sin θ I β = I q cos θ + I d sin θ I_{a}=I_{d}\cos\theta-I_{q}\sin\theta\\I_{\beta}=I_{q}\cos\theta+I_{d}\sin\theta Ia=Idcosθ−IqsinθIβ=Iqcosθ+Idsinθ
SPWM(正弦脉宽调制)
叠加在MOS管的直流电压可以通过PWM开关控制来等效成正弦电压,由于中性点为0,因此电机的相电压也为正弦,从而使得电机相线电流也成正弦变化规则,消除了转矩波动。根据面积等效原理,正弦波还可以等效成PWM波。如图所示,通过这种方式我们不停的调整PWM的占空比来实现正弦电压效应。就是将Sine波叠加到PWM波上输出,在一定程度上PWM的变化就是实际电压的输出。
在实际的控制过程中我们先将Sine波抬到 U d c 2 \frac{U_{dc}}{2} 2Udc处,再利用 U d c U_{dc} Udc得到正值的占空比,即可输出到PWM中进行控制。


SVPWM (空间矢量脉宽调制)技术
SVPWM的核心思想是基于电机定子磁场的空间矢量控制。在电机驱动系统中,逆变器将直流电源转换为三相交流电以驱动电机。SVPWM技术通过精确控制逆变器开关器件的导通与关断时间,使得产生的三相电压合成一个旋转的空间矢量,该矢量可以理想地描绘出一个圆形轨迹,从而模仿理想的三相正弦波形。
简要来说就是,为了使用三相桥的6个MOS管来控制电机,对把6个MOS的8种开关状态进行分析并以向量的方式展现,除去2个零向量就得到了6个非零向量,将其作为6个基向量,可将坐标轴划分为6个扇区。对于任意一个αβ坐标系下的空间矢量将其投影到相邻最近的两个基向量中即可对应到实际的MOS控制。再利用伏秒平衡原则转换成PWM的占空比输出即可实现控制。
-
从开关MOS管到空间矢量合成
下图就是逆变器三相桥臂共有6个开关管,为了研究各相上下桥臂不同开关组合时逆变器输出的空间电压矢量,特定义开关函数
*Sx*(*x*=*a*、*b*、*c)*S x = { 1 上桥臂导通 0 下桥臂导通 S_x=\begin{cases}&1&\text{上桥臂导通}\\&0&\text{下桥臂导通}\end{cases} Sx={10上桥臂导通下桥臂导通

(Sa、Sb、Sc)的全部可能组合共有八个,包括 6个非零矢量Ul(001)、U2(010)、U3(011)、U4(100)、U5(101)、U6(110)、和两个零矢量 U0(000)、U7(111),下面以其中一种开关组合为例分析,假设Sx(x=a、b、c)=(100),此时等效电路如图:
因此相电压可以表示为:(相电压是每相相对于电机中间连接点的电压)
{ U A N = U d c ∗ z z + z 2 = U d c ∗ z 3 Z 2 = 2 3 U d c U B N = − 1 3 U d c U C N = − 1 3 U d c \begin{cases}U_{AN}=U_{dc}*\frac{z}{z+\frac{z}{2}}=U_{dc}*\frac{z}{\frac{3Z}{2}}=\frac{2}{3}U_{dc}\\U_{BN}=-\frac{1}{3}U_{dc}\\U_{CN}=-\frac{1}{3}U_{dc}\end{cases} ⎩ ⎨ ⎧UAN=Udc∗z+2zz=Udc∗23Zz=32UdcUBN=−31UdcUCN=−31Udc
如果我们规定指向中心的方向为正,反之为负,那么此时我们可以画出下图中的三个电压矢量 U a → , U b → , U c → \overrightarrow{U_{a}},\:\overrightarrow{U_{b}},\:\overrightarrow{U_{c}} Ua,Ub,Uc,,(左边),以及它们的合成电压矢量 U → \overrightarrow{U} U,也就是说,这个状态下我们可以认为电机中存在一个矢量 U → \overrightarrow{U} U表征的电压(电流);然后根据右手螺旋定则,可以判断出磁场的磁力线方向,也是和矢量 U → \overrightarrow{U} U一致的。再结合前面章节的分析,转子永磁体会努力旋转到内部磁力线和外部磁场方向一致,所以这个矢量其实就可以表征我们希望转子旋转到的方向,也即所需要生成的磁场方向了。而这个矢量是会不断在空间中旋转的,它的幅值不变,最大为相电压峰值 U d c U_{dc} Udc。

其他几个扇区也是一样的,均可合成这个 U → \overrightarrow{U} U,接下来我们考虑如何合成的问题。
从前面可以知道我们6个基向量,我们根据它能合成的 U → \overrightarrow{U} U的方向放到一个扇区图上。可以看出其余5个空间电压矢量,它们的端点组成了一个正六边形,同时把平面划分成了六个扇区(也就是图中的Ⅰ、Ⅱ、Ⅲ、Ⅳ、Ⅴ、Ⅵ)。

有了这6个方向的力矩我们就可以利用任意两个方向的力矩合成该扇区的任意力矩,也就是能够利用这六个方向的力矩合成任意一个矢量。接下来就只需要求出每个方向的基向量,再将其合成即可得到合力矩,也就是最终的力矩输出。而对于如何合成,我们就用到了伏秒平衡原则。在每一个扇区,选择相邻两个电压矢量以及零矢量,按照伏秒平衡原则来合成每个扇区内的任意电压矢量,即
∫ 0 T U r e f d t = ∫ 0 T x U x d t + ∫ T x T x + T y U y d t + ∫ T x + T y T U 0 ∗ d t \int_0^TU_{ref}dt=\int_0^{T_x}U_xdt+\int_{T_x}^{T_x+T_y}U_ydt+\int_{T_x+T_y}^TU_0^*dt ∫0TUrefdt=∫0TxUxdt+∫TxTx+TyUydt+∫Tx+TyTU0∗dt
所以说我们可以周期性地在不同空间电压矢量之间切换,只要合理地配置不同基向量在一个周期中的占空比,就可以合成出等效的任意空间电压矢量了。接下来我们就从两个问题来继续探究如何得到SVPWM 的占空比,如何判断合矢量在那个扇区?某一个扇区的合矢量如何表示?
-
其一:如何判断合矢量的位置
如下图所示,假定合成的电压矢量落在扇区Ⅰ,其等价条件为 0 < arctan U α U β < π 3 0<\arctan \frac{U_\alpha }{U_\beta} < \frac{\pi }{3} 0<arctanUβUα<3π 故在扇区Ⅰ的充要条件为 U α > 0 U_\alpha>0 Uα>0, U β > 0 U_\beta>0 Uβ>0且 U β U α < 3 \frac{U_{\beta}}{U_{\alpha}}<\sqrt{3} UαUβ<3。

同理我们也可以得到其他的几个扇区的判断标准

观察全部的扇区,很容易就能发现参考电压矢量 U r e f U_{ref} Uref完全是由 U 1 , U 2 , U 3 U_1,U_2,U_3 U1,U2,U3决定的。
{ U 1 = U β U 2 = 3 U α − U β U 3 = − 3 U α − U β \begin{cases}U_1=U_\beta\\U_2=\sqrt3U_\alpha-U_\beta\\U_3=-\sqrt3U_\alpha-U_\beta\end{cases} ⎩ ⎨ ⎧U1=UβU2=3Uα−UβU3=−3Uα−Uβ
且如果定义再定义:
若
*U*1 > 0,则 A=1,否则 A=0;若
*U*2 > 0,则B=1,否则 B=0;若
*U*3 > 0,则 C=1,否则 C=0可以看出 A,B,C 之间共有八种组合,但由判断扇区的公式可知 A,B,C 不会同时为 1 或同时为 0,所以实际的组合是六种,A,B,C 组合取不同的值对应着不同的扇区,并且是一一对应的,因此完全可以由 A,B,C 的组合判断所在的扇区。为区别六种状态,令
N=4*C+2*B+A,则可以通过下表计算参考电压矢量Uref所在的扇区。N 1 2 3 4 5 6 扇区 II VI I IV III V 用上述方法,只需经过简单的加减及逻辑运算即可确定所在的扇区,对于提高系统的响应速度和进行仿真都是很有意义的。如:已知
Uref的*U*β>0,√3*Ua-Uβ*>0,-√3*Ua-Uβ*<0,即:A=1,B=1,C=0,N=3,所以扇区号为I。 -
其二:基本矢量作用时间计算与三相
PWM波形的合成 。为了便于理解先使用作用实际所用时间T的方式来阐述以
Uref处在第Ⅰ扇区时进行分析,如下图所示
Ud就是Udc,即母线电压。下式的最后把Ⅰ扇区两边的电压矢量U4(100)和U6(110)的Uout式子带进来了,分别是2/3Udc和2/3Udc*cos(π/3):[ U α U β ] T S = U r e f [ cos θ sin θ ] T S = 2 3 U d [ 1 0 ] T 4 + 2 3 U d [ cos π 3 sin π 3 ] T 6 \begin{bmatrix}U_\alpha\\U_\beta\end{bmatrix}T_S=U_{ref}\begin{bmatrix}\cos\theta\\\sin\theta\end{bmatrix}T_S=\frac{2}{3}U_d\begin{bmatrix}1\\0\end{bmatrix}T_4+\frac{2}{3}U_d\begin{bmatrix}\cos\frac{\pi}{3}\\\sin\frac{\pi}{3}\end{bmatrix}T_6 [UαUβ]TS=Uref[cosθsinθ]TS=32Ud[10]T4+32Ud[cos3πsin3π]T6
整理求解 T 4 , T 6 , T 0 T_4,T_6,T_0 T4,T6,T0可以得到
T 4 = U α T S − U β T S 3 ∣ U 4 ∣ = 3 T S U d ( 3 2 U α − U β 2 ) = K U 2 T 6 = T 4 = 2 U β T S 3 ∣ U 6 ∣ = 3 T s U d c U β = K U 1 T 0 = T 7 = 1 2 ( T Z − T 4 − T 6 ) \begin{aligned}&T_4=\frac{U_{\alpha}T_{S}-\frac{U_{\beta}T_{S}}{\sqrt{3}}}{\left|U_{4}\right|}=\frac{\sqrt{3}T_{S}}{U_{d}}(\frac{\sqrt{3}}{2}U_{\alpha}-\frac{U_{\beta}}{2})=KU_{2}\\&T_{6}=T_{4}=\frac{2U_{\beta}T_{S}}{\sqrt{3}\left|U_{6}\right|}=\frac{\sqrt{3}T_{s}}{U_{dc}}U_{\beta}=KU_{1}\\&T_{0}=T_{7}=\frac{1}{2}(T_{Z}-T_{4}-T_{6})\end{aligned} T4=∣U4∣UαTS−3UβTS=Ud3TS(23Uα−2Uβ)=KU2T6=T4=3∣U6∣2UβTS=Udc3TsUβ=KU1T0=T7=21(TZ−T4−T6)
同理可求得`*Uref*`在其它扇区中各矢量的作用时间,结果如下表所示。表中两个非零矢量作用时间的比例系数为$K=\frac{\sqrt{3}T_s}{U_dc}$,这个是所有式子的公共项单独表示便于理解。
FOC与SVPWM的对接就变成了,先根据N=4*C+2*B+A判断合成矢量所在扇区,然后查表得出两非零矢量的作用时间,最后得出三相开关管PWM波的占空比,查表让算法更高效。 -
其三:幅值边界
当两个零电压矢量作用时间为0时,一个PWM周期内非零电压矢量的作用时间最长,此时的合成空间电压矢量幅值最大,由下图可知其幅值最大不会超过图中所示的正六边形边界。而当合成矢量落在该边界之外时,将发生过调制,逆变器输出电压波形将发生失真。在
SVPWM调制模式下,逆变器能够输出的最大不失真圆形旋转电压矢量为图2-12所示虚线正六边形的内切圆,其幅值为: 3 2 2 U d c 3 = 3 U d c 3 \frac{\sqrt{3}}{2} \frac{2U_dc}{3}=\frac{\sqrt{3}U_{dc}}{3} 2332Udc=33Udc 。即逆变器输出的不失真最大正弦相电压幅值为 3 U d c 3 \frac{\sqrt{3}U_{dc}}{3} 33Udc ,而若采用三相SPWM调制,逆变器能输出的不失真 最大正弦相电压幅值为 U d c 2 \frac{U_{dc}}{2} 2Udc。显然SVPWM调制模式下对直流侧电压利用率更高,它们的直流利用率之比为 3 U d c 3 ÷ U d c 2 = 1.1547 \frac{\sqrt{3}U_{dc}}{3} {\div} \frac{U_{dc}}{2}=1.1547 33Udc÷2Udc=1.1547,即SVPWM算法比SPWM算法的直流电压利用率提高了15.47%。
如图当合成电压矢量端点落在正六边形与外接圆之间时,已发生过调制,输出电压将发生失真,必须采取过调制处理,这里采用一种比例缩小算法。定义每个扇区中先发生的矢量用为
Tx,后发生的矢量为Ty。当Tx+Ty≤TS时,矢量端点在正六边形之内,不发生过调制;当Tx+Ty>TS时,矢量端点超出正六边形,发生过调制。输出的波形会出现严重的失真,需采取以下措施:设将电压矢量端点轨迹端点拉回至正六边形内切圆内时两非零矢量作用时间分别为*Tx*',*Ty*',则有比例关系: T x ′ T x = T y ′ T y \frac{T_x'}{T_x}=\frac{T_y'}{T_y} TxTx′=TyTy′ 故可以求得*Tx*',*Ty*',T0, T7{ T x ′ = T x T x + T y × T s T y ′ = T y T x + T y × T s T 0 = T 7 = 0 \begin{cases}T_{x}'=\frac{T_{x}}{T_{x}+T_{y}}\times T_{s}\\T_{y}'=\frac{T_{y}}{T_{x}+T_{y}}\times T_{s}\\T_{0}=T_{7}=0\end{cases} ⎩ ⎨ ⎧Tx′=Tx+TyTx×TsTy′=Tx+TyTy×TsT0=T7=0
-
最终作用时间,以及MOS的切换顺序
论上任何切换顺序都是可以的,但是实际中我们需要考虑更多限制,比如因为MOS管存在开关损耗,我们希望能尽量减少MOS管的开关次数,那么以最大限度减少开关损耗为目的,我们就可以设计出下面的切换顺序:对扇区Ⅰ而言

上图中可以看出来,在每个状态切换的时候,都只有一个相发生了转变:**
000**->**100**->**110**->**111**->**110**->**100**->**000,**这也是所谓的七段式SVPWM调制法。同理我们也可以得到其他几个扇区的切换顺序。
SVPWM的工作完成了,我们得到了每一时刻所需要的空间电压矢量以及它们持续的时间,在处理器中赋值给对应通道的捕获比较寄存器产生相应的三个PWM波形,控制MOS管的开关,进而产生我们期望的电压、电流、力矩。
一些概念
Iq 和Id
-
物理意义
变量 名称 物理意义 作用 Iq交轴电流 转矩电流分量 直接控制电机输出转矩 Id直轴电流 励磁电流分量 控制电机磁场强度(弱磁或增磁) 
-
两个参数与转矩的关系(该公式对于所有永磁同步电机)
T e = 3 2 p [ ψ f i q + ( L d − L q ) i d i q ] ∘ p : 极对数 ∘ ψ f : 永磁体磁链 ∘ L d , L q : 直轴 / 交轴电感 T_{e}=\frac{3}{2}p\left[\psi_{f}i_{q}+(L_{d}-L_{q})i_{d}i_{q}\right]\\\circ\:p\colon\text{极对数}\\\circ\:\psi_{f}\colon\text{ 永磁体磁链}\\\circ\:L_{d},L_{q}\colon\text{直轴}/\text{交轴电感} Te=23p[ψfiq+(Ld−Lq)idiq]∘p:极对数∘ψf: 永磁体磁链∘Ld,Lq:直轴/交轴电感
对于表贴式电机而言( L d = L q L_d = L_q Ld=Lq)此时转矩即为
T e = 3 2 p ψ f i q ( 转矩与 i q 成正比 ) T_e=\frac32p\psi_fi_q\quad(\text{转矩与 }i_q\text{ 成正比}) Te=23pψfiq(转矩与 iq 成正比)
- 控制
Iq即直接控制转矩,类似直流电机的电枢电流。
- 控制
-
id不同控制方法的对比控制模式 优点 缺点 适用电机 Id=0 结构简单,铜耗最小 无法利用磁阻转矩 表贴式电机(SPM) Id≠0 可提升转矩(MTPA)/扩速(弱磁) 控制复杂,增加铜耗 内嵌式电机(IPM) -
内嵌式(IPM)和表贴式(SPM)电机
永磁同步电机主要分为**内嵌式(Interior Permanent Magnet, IPM)和表贴式(Surface-mounted Permanent Magnet, SPM)**两种结构
特征 内嵌式电机(IPM) 表贴式电机(SPM) 永磁体位置 嵌入转子内部 粘贴在转子表面 机械强度 高(适合高速运行) 低(需加固措施) 凸极效应 明显(Ld<Lq) 无(Ld≈Lq) 转矩来源 永磁转矩 + 磁阻转矩 主要依赖永磁转矩
Iq 和力矩之间的关系
得到了 I q Iq Iq值我们需要将其转换成转矩才能有实际的闭环控制。很多地方对这个力矩和转矩的概念很模糊。这里贴出DeepSeek的回答,且后续阐述均已转矩为主。
在电机领域,“转矩”、“扭矩”和“力矩”这三个术语本质上指的是同一个物理概念,即使物体发生旋转或扭转的物理量。它们之间的区别更多是使用习惯和语境上的细微差别,而非严格的物理定义不同。
| 术语 | 核心含义 | 主要应用场景/细微差别 | 在电机中的典型用法 |
|---|---|---|---|
| 力矩 | 使物体转动效果的物理量 | 最广泛、最基础的概念 (杠杆、静力学等) | 指电机内部产生的电磁力矩 |
| 转矩 | 旋转系统中的力矩 | 旋转机械(电机、发动机)的首选标准术语 | 输出转矩、额定转矩、堵转转矩 |
| 扭矩 | 旋转系统中的力矩 | 与转矩同义,常用于机械应力分析、日常口语化 | 可替代“转矩”使用,指电机输出的旋转力 |
那么如何实现转矩的闭环控制呢?我们查看灯哥的DengFOC对其的解释。
而Iq在一定程度上是能够代表电机力矩的,只需要电机的KV值,就能够通过下面的式子把Iq换算成电机力矩:
Torque [N.m] = 8.27 * Iq [A] / KV. \text{Torque [N.m] = 8.27 * Iq [A] / KV.} Torque [N.m] = 8.27 * Iq [A] / KV.
总有一种说不出来的感觉,所以说我们还是自己推到试试。前面我们已经得到,其中的p和 I q Iq Iq值我们可以直接得到,主要是永磁体磁链 ψ f \psi_f ψf
T e = 3 2 p ψ f I q ( 转矩与 I q 成正比 ) T_e=\frac32p\psi_fI_q\quad(\text{转矩与 }I_q\text{ 成正比}) Te=23pψfIq(转矩与 Iq 成正比)
磁链( ψ f \psi_f ψf ,也称为磁通或磁通链)由电机中的永磁体所产生,电机的转子上产生一个固定的磁场,这个磁场与电机的定子上的绕组之间产生磁链,磁链的分布决定了电机中的磁场强度和方向,影响着电机的性能和运行特性。
无刷电机既是电动机也是发电机,在不通电时,转子在人为情况下转动,切割磁感线形成感应电动势,也就是我们的反电动势;而我们的反电动势信息又和磁链息息相关。
这里给出一种网友的方法:想办法让电机在夹好示波器的情况下旋转几圈,反高低转速下磁链值变化并不大。从而再示波器中我们可以得到电机反电动势,频率等信息,从而可以求出我们的磁链值(公式如下)。**Ts 为周期值,Vpp为电压峰峰值, 具体的操作参考【https://blog.csdn.net/m0_64461937/article/details/148841169】**里面也介绍了反电动势的计算方法,也可利用反电动势求解转矩常数 K t = 3 2 p ψ f = 60 2 π K e K_t=\frac32p\psi_f=\frac{60}{2\pi K_e} Kt=23pψf=2πKe60 Ke即为反电动势常数
ψ f = V p p ∗ T s 4 π ∗ 3 \psi_f=\frac{Vpp*Ts}{4\pi^*\sqrt{3}} ψf=4π∗3Vpp∗Ts
STM32的PWM
-
定时器中的
auto-reload preload参数解释*auto-reload precload=Disable:自动重装载寄存器写入新值后,计数器立即产生计数溢出,然后开始新的计数周期**auto-reload precload=Enable:自动重装载寄存器写入新值后,计数器完成当前旧的计数后,再开始新的计数周期* -
PWM模式:PWM模式1,向上计数时,PWM信号从有效电平变为无效电平PWM模式2,向上计数时,PWM信号从无效电平变为有效电平 -
PWM极性:极性为高时,高电平为有效电平,低电平为无效电平
极性为低时,低电平为有效电平,高电平为无效电平
-
定时器的中央对其模式(先向上再向下计数)
1:仅在向下计数时产生比较中断
2:仅在向上计数时产生比较中断
3:向下和向上计数均产生比较中断中心对齐模式
PWM频率是普通模式的一半,会产生上溢和下溢两个update事件,均可触发更新中断。
STM32的ADC
-
采样时间
在开始转换之前,ADC必须在被测电压源 和ADC的嵌入式采样电容之间建立直接连接。这个 采样时间必须足以使输入电压源将嵌入式 电容器充电到输入电压水平。
每个通道可以用不同的采样时间进行采样,这是可编程的,使用 ADC_SMPR1和ADC寄存器中的SMP[2:0]位。因此,可以在以下采样时间值中选择 :

总的转换时间计算
T C O N V = S a m p l i n g t i m e + 12.5 A D C c l o c k c y c l e s \mathrm{T_{CONV}=Sampling~time+12.5~ADC~clock~cycles} TCONV=Sampling time+12.5 ADC clock cycles
即在ADC的频率为
42.5Mhz情况下,使用6.5个采样周期,实际ADC需要的时间为:t = ( ( 6.5 + 12.5 ) / 42.5 ) ∗ 1 0 − 6 = 447 n s t=((6.5+12.5)/42.5)*10^-6=447ns t=((6.5+12.5)/42.5)∗10−6=447ns
-
与定时器进行联动
在使用ADC的采样过程中,我们平常都是直接使用软件自动触发采样,我们在需要数据的时候再读取出来,但实际上ADC的采样可以有很多的触发方式,定时器就是其中最有用的方式,这里我们使用定时器的方式去与控制端进行联动,至于为啥,后面会提到。
在配置好定时器后我们在
Trigger Output (TRGO)Parameters里面打开更新事件
再在ADC中的外部触发转换源(External Trigger Conversion Source)中选择对应定时器的触发源,如果使用的PWM的比较输出,选择对应的【Compare】就行这里用的定时器。

设置好了我们考虑一下他是什么时候触发的采样,可以看到我都RCR值设定的1,从下图中可以看到在中心对齐模式会经过一次上溢和一次下溢才产生中断。也就是说在完整走完一个PWM周期后就触发一次ADC采样

下图是打开定时器的事件更新中断,并在其中添加一个电平反转函数的输出,最后一个是电平输出,可以看到每次完成一个周期的
PWM后都会触发一次电平反转且其周期为10KHz(但是ARR设错了,应该是10K)我们的载波频率为20KHz
SPWM和SVPWM
来源于DeepSeek
| 特点 | SPWM (正弦脉宽调制) | SVPWM (空间矢量脉宽调制) |
|---|---|---|
| 基本原理 | 相电压调制:将正弦波参考信号与三角载波比较,独立生成三相PWM。 | 空间矢量合成:将三相系统视为一个旋转矢量,用逆变器的8个基本开关矢量(6有效+2零)合成目标参考矢量。 |
| 电压利用率 | 较低:最大输出相电压基波幅值 ≈ Vdc / 2 (0.5 Vdc) |
较高:最大输出相电压基波幅值 ≈ Vdc / √3 ≈ 0.577 Vdc (比SPWM高15.47%) |
| 谐波性能 | 相对较高:电流THD较大,谐波能量分散。 | 更优:电流波形更正弦,THD更低,谐波能量更集中在高频(易滤波)。 |
| 算法复杂度 | 简单:每相独立计算,实现容易。 | 较复杂:需要坐标变换、扇区判断、矢量作用时间计算、优化开关序列。 |
| 开关损耗 | 相对较高:每相开关频率固定,但序列未优化。 | 更低:优化的七段式开关序列使每个桥臂在一个周期内只开关一次,减少损耗。 |
| 目标导向 | 追求每相电压波形接近正弦。 | 追求合成磁链轨迹接近圆形(电机转矩更平稳)。 |
| 主要优势 | 实现简单,计算量小。 | 电压利用率高、效率高、电流谐波小、转矩脉动小、动态响应好。 |
| 典型应用 | 对性能要求不高的简单变频器。 | 主流高性能应用:伺服驱动、电动汽车、精密控制、要求高效率低噪声的场合。 |
极对数
**定义:**极数是指电机定子磁场中磁极的总数量,通常以极对数§表示。每个极对包含一个北磁极(N)和一个南磁极(S)。
**作用:**极数决定了电机的同步转速,转速与电源频率(f)和极对数§的关系为:同步转速=120f/p(对于60Hz系统),或同步转速=60f/p(对于50Hz系统)。
**影响:**极数影响电机的扭矩、速度范围和噪音水平。极数越多,电机的转速越低,但通常能产生更高的扭矩。

电角度和机械角度
机械角度就是转子相对于定子旋转的角度,就是人看到的角度。
电角度: 一个点的磁极发生变化从N到S级 变化的时候,代表电角度是180度(这个很多人都不讲)。所以电角度=极对数(或者级数/2)*机械角度

内嵌式和表贴式电机
| 特征 | 内嵌式电机(IPM) |
表贴式电机(SPM) |
|---|---|---|
| 永磁体位置 | 嵌入转子内部 | 粘贴在转子表面 |
| 机械强度 | 高(适合高速运行) | 低(需加固措施) |
| 凸极效应 | 明显(Ld<Lq) | 无(Ld≈Lq) |
| 转矩来源 | 永磁转矩 + 磁阻转矩 | 主要依赖永磁转矩 |
电流采样方式
主要分为:低端的单电阻,双电阻,三电阻,高端采样
-
高端采样:
如图(红色波形),直接采样桥臂输出电流,软件上无需再进行电流重构计算,采样值即真实输出电流,方便,但成本过高。由于该位置采样所选器件需要承受母线电压,在电源非隔离条件下,运放的抗共模电压指标需要大于等于母线电压(多数选母线电压的2倍),否则无法正常工作。而电源隔离条件下,其参考地(
GND)不同,所以无需考虑该问题。因为电机三相电流遵循Ia+Ib+Ic=0,故实际实现时只需采样任意两相电流即可获得完整三相输出电流
-
低端三通道(双通道)采样
采样三相下桥臂电流来获取有效数据,在具体操作时无需软件重构,仅需判断扇区位置,确定需要采样的桥臂即可,虽实现简单,但相较于双电阻采样多使用了一个运放,故成本介于双电阻采样和高端采样之间。低端

电阻放在下管采集的是续流电流,我们在下桥开通的中点进行采样,此时对应的电流反映了平均电流,因此对应的电流控制就是平均电流控制。使用的是三电阻方式采样的话,选用的ADC模块必须至少要有三个通道同时采样的功能,这样才能确保采样三相相电流是同一时刻的电流,此时才能保证
Iu+Iv+Iw=0,这个公式成立。下图是ST电机库的方案,也解释了之前的ADC和TIM联合的原因
当然还有一种双电阻采样的方式,但双电阻采样无法避免窗口时间,所以需要限制最终
PWM的占空比,为ADC转换预留足够的时间;
-
低端单通道采样
单电阻采样需要在一个
PWM周期内进行两次采样,下面需要在SVPWM六个扇区进行相电流的分类,这里可以对SVPWM的原理进行分析,从而了解如何对电流进行重构;单电阻的电路结构如下图所示;
为了便于理解整个采样的过程,为了表示逆变器的开关管的状态,
Sa表示A相的上下管,同理Sb表示B相的上下管;这里规定:
Sa = 1表示上管导通,下管断开;Sa = 0表示下管导通,上管断开;Sb和Sc以此类推;Sa Sb Sc:100
Sa Sb Sc:110
SVPWM的开关状态开关状态 AH BH CH 电流 0 0 0 0 0 1 1 0 0 IA 2 1 1 0 −IC−IC 3 0 1 0 IBIB 4 0 1 1 −IA−IA 5 0 0 1 IC 6 1 0 1 −IB−IB 7 1 1 1 0 因此,单电阻采样,需要在一个
PWM周期内进行两次采样;具体如下图所示;
图中的SAL,SBL,SCL分别对应整流桥的下管,因此在一个周期内分别进行了
Sample 1和Sample 2这两次采样,对照上表可以推出;-
Sample 1:采集了开关管状态为
SAL SBL SCL:101==>SAH SBH SCH:010,此时采样电流为 IB;IB
-
Sample 2:采集了开关管状态为
SAL SBL SCL:100==>SAH SBH SCH:011,此时采样电流为 −IA;−IA
原理搞清楚之后,下面要注意的地方还有两点采样点的确认和窗口时间的限制;以下是ST的方案

-
硬件设计
由于电机比较小,就不考虑使用MOS外置的方案,最好使用内置MOS的方案,后面经过查找发现使用MPS的MP654比较合适。编码器使用15bit的TLE5012 以下几个比较关键的IC说明
-
器件选择
STM32G431:STM32G4系列是STMicroelectronics推出的混合信号微控制器,基于 32 位Arm®Cortex®-M4内核,支持FPU和DSP指令集,主频高达 170 MHz。该系列微控制器结合了三种不同的硬件加速器:ART Accelerator™、CCM-SRAM例程加速器和数学加速器,G4相比其他系列(比如F4或者L4)提升了内核性能、外设集成、能效比、数学加速模块等MP6540:MP6540解决了传统电机驱动器架构的缺点。它可以在高达35V**的电源电压下工作,并支持 100% 占空比操作**。[MP6540 61](https://www.monolithicpower.cn/mp6540-mp6540a.html)具有低导通电阻、集成双向电流采样放大器和故障指示输出等特性。它集成了6个MOSFET及其相应驱动器,并采用小尺寸QFN-26 (5mmx5mm)封装。其集成电流采样电路可以在每个桥臂的下管MOSFET中进行双向电流测量,从而避免了外部电流采样电路带来的尺寸与成本问题。[MP6540](https://www.monolithicpower.cn/mp6540-mp6540a.html) 还具有过温保护 (OTP)、欠压锁定 (UVLO)和过温关断等保护功能。TLE5012BE:TLE5012B角度传感器基于iGMR技术,可检测平行于封装表面磁场 360°变化。可应用于汽车和工业领域里转角位置检测如方向盘转角,电机位置等。TLE5012B具备极其精确的角度分辨率(15bit)以及快速的信号处理能力和较短的延时/更新率,极其适合精确测定高动态应用中的转子位置。同时TLE5012B具有先进的诊断功能及安全特性,确保了产品高可靠性。
-
原理图设计
添加了一个
EEPROM,但不知道怎么了软件驱动不了!!!!
-
PCB设计
我想尽量贴合电机,就把板子设计设计成了下面的样子



代码实现
MATLAB Simulink仿真
这里由于本人时间有限未能把所有相关的MATLAB的闭环控制都写出,但基于下面的模型后续加上几个闭环控制基本就能验证FOC的所有功能了。
-
其一 Clark Park变换
单纯的了解算法毫无意义,我们更需要去实际的做仿真和实物来验证才能将其转换成生产力。所以说在了解完成算法后我们使用MATLAB来验证我们算法是否正确。
在MATLAB Simulink中有现成的Clark,Park变换的模块,我们可以直接使用官方的库,而且官方的库的手册也写的很漂亮。下图是使用官方的库来做的仿真,仿真的Scope此处就不放了。

但我建议还是借用我们以及推导的公式来实际做一下仿真,如下图。

此处我使用模块的方式将每种算法变换独立封装。每个模块里面MTLAB的函数实现算法。至于如何实现这些东西,可以跟一下MATLAB官方做的,很不错的一个课【https://www.bilibili.com/video/BV1Kz4y1r7ep/?spm_id_from=333.337.search-card.all.click&vd_source=ee41073581b94a0ba0c58d77a73012c6】

我们现在来分析每一个变换的生成的图
-
Clark变换对应前图的①的示波器,对其的输入是三个相位差120°的幅值为10正弦波。输出则为相位差90°的波形,也就是我们将电流值(电压)从三相的三维ABC坐标系转换成了
αβ坐标系。这里我使用官方的图。
-
得到
αβ坐标系的Alpha,Beta值后我们也可以用逆Clark变换将其转换回去。如下图一样对应着经过Clark变换和逆Clark变换的对比。可以看到与原波形一致。
-
对于Park变换而言我们需要给它输入一个θ角度此处我们直接选择一个递减的范围在[0,2*pi]的锯齿波用以模拟转子的运动一周。下图为示波器③的波形其中的红色即为我们输入的锯齿波,蓝色即为Q值,黄色为D值。

-
跟之前的Clark变换一样我们再使用逆Clark变换把输入信号还原回来如示波器④所示

-
-
其二
SVPWM对于
SPWM使用逆Clark变换后的三相电压值作为待调制波,将其变换到电源电压的一半做归一化得到需要的PWM的占空比,以此输出PWM即可。本文主要还是以SVPWM为主,前面可以得到我们我们将Park变化得到的Alpha,Beta值,利用这两个值很容易就能合成U V W三相的PWM占空比输出。一下是MATLAB的SVWM模块代码(此处输出为占空比):-
MATLAB代码
function [Ua,Ub,Uc, N, Duty_x,Duty_y,Duty_z,U, V, W] = SVPWM_Converter(Udc, Ualpha, Ubeta) % SVPWM转换器 % 输入: % Udc - 电源电压 (V) % Ualpha, Ubeta - αβ坐标系电压分量 % 输出: % Ua Ub Uc % 扇区此处为计算出的N值 % 当前相位的Duty值 % 输出PWM的占空比 % 定义常数 SQRT_3 = sqrt(3); % 计算扇区判断变量 Ua = double(Ubeta); Ub = double((SQRT_3 * Ualpha - Ubeta) / 2.0); Uc = double((-SQRT_3 * Ualpha - Ubeta) / 2.0); % 确定扇区 (1-6) N = 0; N = N + (Ua > 0); N = N + 2 * (Ub > 0); N = N + 4 * (Uc > 0); % 计算基本占空比 K = SQRT_3 / Udc; %N值和实际的扇区是不同的 switch N case 3 % Sector 1 (001) Duty_x = K * Ub; Duty_y = K * Ua; case 1 % Sector 2 (010) Duty_x = -K * Ub; Duty_y = -K * Uc; case 5 % Sector 3 (011) Duty_x = K * Ua; Duty_y = K * Uc; case 4 % Sector 4 (100) Duty_x = -K * Ua; Duty_y = -K * Ub; case 6 % Sector 5 (101) Duty_x = K * Uc; Duty_y = K * Ub; case 2 % Sector 6 (110) Duty_x = -K * Uc; Duty_y = -K * Ua; otherwise % 无效扇区 Duty_x = 0; Duty_y = 0; end % 占空比归一化处理 sum_xy = Duty_x + Duty_y; if sum_xy > 1.0 Duty_x = Duty_x / sum_xy; Duty_y = Duty_y / sum_xy; end % 计算零序列分量 Duty_z = (1 - Duty_x - Duty_y) * 0.5; % 计算三相占空比 switch N case 3 % Sector 1 U = Duty_z; V = Duty_x + Duty_z; W = Duty_x + Duty_y + Duty_z; case 1 % Sector 2 U = Duty_x + Duty_z; V = Duty_z; W = Duty_x + Duty_y + Duty_z; case 5 % Sector 3 U = Duty_x + Duty_y + Duty_z; V = Duty_z; W = Duty_x + Duty_z; case 4 % Sector 4 U = Duty_x + Duty_y + Duty_z; V = Duty_x + Duty_z; W = Duty_z; case 6 % Sector 5 U = Duty_x + Duty_z; V = Duty_x + Duty_y + Duty_z; W = Duty_z; case 2 % Sector 6 U = Duty_z; V = Duty_x + Duty_y + Duty_z; W = Duty_x + Duty_z; otherwise % 无效扇区 U = 0; V = 0; W = 0; end end
我们在前面给一个逆Park变换的Alpha,Beta值如下图所示:

把所有的信号全部接到示波器里面,即可得到下图,最后一个即为我们最后的
SVPWM占空比输出(漂亮的马鞍波)
第一个波形是
Ua Ub Uc的输出很像Clark变换后的波形,但实际不是的,翻翻前面的解释,第二个是利用
Ua Ub Uc算出的N值,这里N值变换规律是3→1→5→4→6→2,但这不是实际的扇区。第三个即为计算出的扇区基本本矢量作用时间。
第四个为
SVPWM的实际输出,大部分文章都是在前面就加上了载波的实际周期,但我觉得理解很麻烦,就用了占空比作为最终输出,而对其他的以及乘上了周期的输出即为PWM的比较值(也就是对应的STM32的CCR值) -
-
其三 电机仿真
得到了
PWM的占空比,接下来我们就可把他给到PWM转换器,输出PWM给到电机。这里没有做闭环控制,指示简单做了一个开环的系统验证。我试过该模型是可以是可以实现闭环控制的。
在得到
SVPWM的占空比后我们将其输入到一个PWM生成器中,此处为了方便解释STM32中央对其下的PWM输出,自己画一个PWM生成器,并输入一个三角波得到六路的PWM输出或者三路的PWM输出,六路的主要对应与那种上下管都要控制的。对应前图②波形如下
第一个即为三角波(载波)第二个是最终的输入,第三个我将三个
PWM分开了,便于查看理解,第四个即为最终的输出有点不直观,但缩小又丢失的细节。我们调用一个三相全桥,由于该桥是用6相驱动(也就是上下管都要驱动),我们使用6路的作为输入,经过全桥后输入到电机中(这个电机我还不怎么会用,只会简单看一些参数)电机和全桥中间是一个三相带电压电流监测器,可以帮我们监测相电流电压或者线电流电压,下图为相电流电压监测,感兴趣的可以试试给三个相电压过一个低通滤波器。并且我们可以看到其电流输出是三相相位差120°(可能看着有偏差),后面我们就可以用Clark以及Park变换得到D,Q值来闭环了。对应前面的③示波器。

实际代码实现
-
FOC闭环控制
这里用串行的PID也行,对速度或者角度做单独的闭环也可,只需确定好输入输出和参考就行,拿PID套就行。
-
SVPWMC语言实现void SVPWM_SetPWM(float power_vol, float Ualpha, float Ubeta){ //获取扇区位置 float Ua = Ubeta; // 计算Ua float Ub = (SQRT_3 * Ualpha - Ubeta) / 2.0f; // 计算Ub float Uc = (-SQRT_3 * Ualpha - Ubeta) / 2.0f; // 计算Uc Sector_t sector = Sector_NULL; // 初始化扇区为Sector_NUL sector += (Ua > 0) ? 1 : 0; // 根据Uc的符号确定扇区 sector += (Ub > 0) ? 2 : 0; // 根据Ub的符号确定扇区 sector += (Uc > 0) ? 4 : 0; // rt_kprintf("%d,%.2f,%.2f,%.2f\n",sector,Ualpha*100,Ubeta*100,Uc*100); // 调试输出 //计算duty float Duty_x=0.0f, Duty_y=0.0f, Duty_z=0.0f; float K = SQRT_3 / power_vol; switch(sector){ case Sector_1: Duty_x = K * Ub; Duty_y = K * Ua; break; case Sector_2: Duty_x = -K * Ub; Duty_y = -K * Uc; break; case Sector_3: Duty_x = K * Ua; Duty_y = K * Uc; break; case Sector_4: Duty_x = -K * Ua; Duty_y = -K * Ub; break; case Sector_5: Duty_x = K * Uc; Duty_y = K * Ub; break; case Sector_6: Duty_x = -K * Uc; Duty_y = -K * Ua; break; default: Duty_x = 0.0f; Duty_y = 0.0f;break; } float sum = Duty_x + Duty_y; if(sum > 1.0f){// 如果总和大于1,则进行归一化处理 Duty_x /= sum; Duty_y /= sum; } // 计算第三相的占空比 Duty_z=(1-Duty_x-Duty_y)*0.5f; // rt_kprintf("%d,%.3f,%.3f,%.3f\n",sector, (Duty_x+Duty_y+Duty_z)*100, (Duty_x+Duty_z)*100, Duty_z*100); // 调试输出 float U=0.0f, V=0.0f, W=0.0f; // 将占空比转换为PWM值 switch(sector){ case Sector_1: U = Duty_z; // U相 V = Duty_x + Duty_z; // V相 W = Duty_x + Duty_y + Duty_z; // W相 break; case Sector_2: U = Duty_x + Duty_z; // U相 V = Duty_z; // V相 W = Duty_x + Duty_y + Duty_z; // W相 break; case Sector_3: U = Duty_x + Duty_y + Duty_z; // U相 V = Duty_z; // V相 W = Duty_x + Duty_z; // W相 break; case Sector_4: U = Duty_x + Duty_y + Duty_z; // U相 V = Duty_x + Duty_z; // V相 W = Duty_z; // W相 break; case Sector_5: U = Duty_x + Duty_z; // U相 V = Duty_x + Duty_y + Duty_z; // V相 W = Duty_z; // W相 break; case Sector_6: U = Duty_z; // U相 V = Duty_x + Duty_y + Duty_z; // V相 W = Duty_x + Duty_z; // W相 break; default: U = 0.0f; // U相 V = 0.0f; // V相 W = 0.0f; // W相 break; } // rt_kprintf("%d,%f,%f,%f\n",sector, U*CCR_MAX, V*CCR_MAX, W*CCR_MAX); // 调试输出 // 将占空比转换为PWM值 htim1.Instance->CCR1 = (uint16_t)(U * CCR_MAX); htim1.Instance->CCR2 = (uint16_t)(V * CCR_MAX); htim1.Instance->CCR3 = (uint16_t)(W * CCR_MAX); } -
SPWMC语言实现/** * @brief: 将电压 Uq 和 Ud 转换为三相电压 Ua, Ub, Uc * @param Ud: d轴电压 * @param Uq: q轴电压 * @param angle_el: 电角度 * @param Ua, Ub, Uc: 输出的三相电压 * @note: 使用帕克逆变换和克拉克逆变换来计算三相电压 * @公式:帕克逆变换 * | U_alpha | = | cos(theta) -sin(theta) | x | U_d | * | U_beta | | sin(theta) cos(theta) | | U_q | * * 克拉克逆变换 * * | U_a | = | 1 -1/2 | x | U_alpha | * | U_b | | 0 sqrt(3)/2 | x | U_beta | * * | U_c | | 0 -sqrt(3)/2 | * * */ void SPWM_Ctrl( float Uq, float Ud, float angle_el, float power_vol){ // 帕克逆变换 float Ualpha=0, Ubeta=0; arm_inv_park_f32(Ud, Uq, &Ualpha, &Ubeta, arm_sin_f32(angle_el), arm_cos_f32(angle_el)); float Ua=0, Ub=0, Uc=0; // 克拉克逆变换 arm_inv_clarke_f32(Ualpha, Ubeta, &Ua, &Ub); Uc = -Ua - Ub; // 计算第三相 // rt_kprintf("%f,%f,%f,%f,%f\n",Ualpha,Ubeta,angle_el, *Ua, *Ub); // 调试输出 SPWM_SetPWM(power_vol, Ua, Ub, Uc); // 设置PWM输出 } /** * @brief : 将三相电压 Ua, Ub, Uc 转换为电压 Uq 和 Ud * @param vol : 电源电压 * @param Ua : A相电压 * @param Ub : B相电压 * @param Uc : C相电压 */ void SPWM_SetPWM(float vol, float Ua, float Ub, float Uc){ Ua += vol/2;//将其偏移到输入电压的一半 Ub += vol/2; Uc += vol/2; Ua = Constrain(Ua / vol, 0.0f , 1.0f ); Ub = Constrain(Ub / vol, 0.0f , 1.0f ); Uc = Constrain(Uc / vol, 0.0f , 1.0f ); //写入PWM到PWM 0 1 2 通道 htim1.Instance->CCR1=Ua*CCR_MAX;//调节占空比 htim1.Instance->CCR2=Ub*CCR_MAX;//调节占空比 htim1.Instance->CCR3=Uc*CCR_MAX;//调节占空比 // rt_kprintf("%d,%d,%d,%d,%d\n",HAL_GPIO_ReadPin(PWM1_GPIO_Port, PWM1_Pin), // HAL_GPIO_ReadPin(PWM2_GPIO_Port, PWM2_Pin),HAL_GPIO_ReadPin(PWM3_GPIO_Port, PWM3_Pin),TIM1->CCR1,TIM1->CNT); } -
PID闭环控制/** * @brief : 电机控制线程入口函数 * @author JCML * @return NULL */ void Motor_Control_Thread_entry(void *parameter){ pid_init(&pid_angle, PID_POSITION, Param_Angle_PID); // 初始化角度PID pid_init(&pid_speed, PID_POSITION, Param_Speed_PID); // 初始化速度PID pid_init(&pid_Id, PID_POSITION, Param_Id_PID); // pid_init(&pid_torque, PID_POSITION, Param_Torque_PID); // 初始化d轴电流PID first_order_filter_init(&filter_Iq, 0.002f, 0.2f); // 初始化Iq滤波器 first_order_filter_init(&filter_Id, 0.002f, 0.05f); // 初始化Id滤波器 FOC_init(motor_svpwm); // 初始化电机 while(RT_TRUE){ #if defined(MOTOR_NEED_CALIBRATION) && MOTOR_NEED_CALIBRATION == 1 Motor_calibration(); // 电机标定 rt_thread_mdelay(1000); // 延时1秒 #else rt_mq_recv(senser_mq, &data, sizeof(SenserData_t), RT_WAITING_FOREVER); Iq_Id_Calculate(data.Current_A, data.Current_B, data.Current_C, electricalAngle(data.angle), &Iq, &Id); // 计算Iq和Id Iq = first_order_filter_calc(&filter_Iq, Iq)-0.0062f; // 滤波Iq+偏移补偿 Id = first_order_filter_calc(&filter_Id, Id); // 滤波Id float target = 0.0f; //角度的边界处理 #if (MOTOR == 1) BOUNDARY_PROCESS(target,data.angle-target_angle,0, 2*PI); pid_calc(&pid_angle, -target, 0.0f); // 计算角度PID输出 pid_calc(&pid_speed, data.speed,pid_angle.out); // 计算速度PID输出50*RX_Value/100.0f pid_calc(&pid_torque, Torque_Culc(Iq,Id), -pid_angle.out); // 计算q轴电流PID输出 RX_Value*0.05f MAX = 1.3 // pid_calc(&pid_Id, Id, 0.0f); setPhaseVoltage(pid_torque.out, 0.0f, electricalAngle(data.angle), data.voltage, SVPWM_MODE); // 设置电压 // #elif (MOTOR == 2) #endif pid_clear(&pid_speed); // 清除PID状态 pid_clear(&pid_torque); // 清除PID状态 pid_clear(&pid_Id); // 清除PID状态 rt_thread_mdelay(1); #endif // DEBUG } } -
电机初始校准
资料
算法相关
- 【自制FOC驱动器】深入浅出讲解FOC算法与SVPWM技术 - 知乎
- https://www.eet-china.com/archives/37283.html
- https://blog.csdn.net/csol1607408930/article/details/123852742
- FOC?看这篇文章就够了 - 知乎
- https://blog.csdn.net/K_O_R_K/article/details/123546950
- https://www.cnblogs.com/fortunely/p/18986181
- https://blog.csdn.net/yasdasdp/article/details/149039317
- https://www.cnblogs.com/FBsharl/p/19005618
- 无刷电机的工作原理,动图演示,一目了然 - 知乎
- https://blog.csdn.net/Eysent/article/details/90581198
- https://blog.csdn.net/qq_31074045/article/details/141636074
- http://www.gitweixin.com/?p=3712
- 澄远FOC笔记–SVPWM原理以及实现-CSDN博客
- https://blog.csdn.net/qlexcel/article/details/74787619
- https://blog.csdn.net/u010632165/article/details/110889621
开发相关
- https://www.bilibili.com/video/BV1Kz4y1r7ep/?spm_id_from=333.337.search-card.all.click&vd_source=ee41073581b94a0ba0c58d77a73012c6
- https://www.latexlive.com/
- 【经验分享】STM32开启浮点运算单元FPU与DSP运算库,附性能测试 - STM32团队 ST意法半导体中文论坛
- CMSIS-DSP: Overview
- https://www.cnblogs.com/yfceshi/p/18995497
- https://blog.csdn.net/qq_38295600/article/details/132904072
- https://blog.csdn.net/qq_35629563/article/details/118675981
- https://blog.csdn.net/raominping/article/details/132621152
- SimpleFOC中文官方
- https://dengfoc.com/#/
- 无刷直流电机转速与电压(电流)的关系,(本人探索篇) - 知乎
- https://blog.csdn.net/m0_64461937/article/details/148841169
- https://blog.csdn.net/qq_42681425/article/details/134489649
- 图解边沿对齐,中心对齐PWM… - 知乎
- https://zhuanlan.zhihu.com/p/707012741
- FOC 电流采样方案对比(单电阻/双电阻/三电阻) - 小麦大叔 - 博客园
更多推荐



所有评论(0)