FOC - SVPWM扇区计算Part1


【全文大纲】 : https://blog.youkuaiyun.com/Engineer_LU/article/details/135149485


1 . 概要

经过扇区判断后,就知道在哪个扇区进行输出了
【Q】但是每个扇区分别输出怎样的结果呢?
【A】这篇博文详述了这个意义

2 . 扇区计算

这里一开始先把六个扇区的TxTy结果列出来,方便看到文章开头记住扇区关系,后面内容对每个扇区有 详细推导过程

扇区TxTy
3 T s U d c ( 3 2 U α − 1 2 U β ) \frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α-\frac 1 2Uβ ) Udc3 Ts(23 Uα21Uβ) 3 T s U d c U β \frac {\sqrt3 T_s}{U_{dc}}Uβ Udc3 TsUβ
3 T s U d c ( − 3 2 U α + 1 2 U β ) \frac {\sqrt3 T_s}{U_{dc}}(-\frac {\sqrt3}2U_α+\frac 1 2Uβ ) Udc3 Ts(23 Uα+21Uβ) 3 T s U d c ( 3 2 U α + 1 2 U β ) \frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α+\frac 1 2Uβ ) Udc3 Ts(23 Uα+21Uβ)
3 T s U d c U β \frac {\sqrt3 T_s}{U_{dc}}Uβ Udc3 TsUβ − 3 T s U d c ( 3 2 U α + 1 2 U β ) -\frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α+\frac 1 2Uβ ) Udc3 Ts(23 Uα+21Uβ)
− 3 T s U d c U β -\frac {\sqrt3 T_s}{U_{dc}}Uβ Udc3 TsUβ 3 T s U d c ( − 3 2 U α + 1 2 U β ) \frac {\sqrt3 T_s}{U_{dc}}(- \frac {\sqrt3}2U_α+\frac 1 2Uβ ) Udc3 Ts(23 Uα+21Uβ)
− 3 T s U d c ( 3 2 U α + 1 2 U β ) -\frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α+\frac 1 2Uβ ) Udc3 Ts(23 Uα+21Uβ) − 3 T s U d c ( − 3 2 U α + 1 2 U β ) -\frac {\sqrt3 T_s}{U_{dc}}( -\frac {\sqrt3}2U_α+\frac 1 2Uβ ) Udc3 Ts(23 Uα+21Uβ)
3 T s U d c ( 3 2 U α + 1 2 U β ) \frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α+\frac 1 2Uβ ) Udc3 Ts(23 Uα+21Uβ) − 3 T s U d c U β -\frac {\sqrt3 T_s}{U_{dc}}Uβ Udc3 TsUβ

>这里讲一下扇区计算的概念
【Q】前面计算了许多步骤最终把UαUβ送进SVPWM,那么怎么把UαUβ与SVPWM产生关联?
【A】答案是基于之前相电压合成关系代入
U α = U m c o s θ U_α = U_mcosθ Uα=Umcosθ
U β = U m s i n θ U_β = U_msinθ Uβ=Umsinθ
U m = 2 3 U d c U_m = \frac 2 3 U_{dc} Um=32Udc, 为什么是 2 3 U d c \frac 2 3U_{dc} 32Udc因为在SVPWM控制中,硬件的三组开关管里每一组时时刻刻都在开关状态,而形成回路中最多两路进,一路出,因此同一时刻相对 U d c U_{dc} Udc最多用到了 2 3 \frac 2 3 32

在这里插入图片描述


接下来如上图矢量圆所示,扇区Ⅰ, Ⅱ, Ⅲ, Ⅳ, Ⅴ, Ⅵ,矢量分别为U4 (100),U6 (110),U2 (010),U3 (011),U1 (001),U5 (101)
另外图中的α和β就是上述描述的UαUβ。

我们想要在这个 矢量圆 里输出N个不同大小,方向的矢量从而来控制电机力矩,但是我们只有六个基本矢量U4-U6-U2-U3-U1-U5,那怎么输出我们想要的矢量?这里我们只要基于六个基本矢量进行合成就可以了,具体根据每个扇区相邻的两个基本矢量进行合成,以下开始对每个扇区计算合成矢量。

在这里插入图片描述

这里以扇区一举例,如图所示把合成的矢量U设为 U o u t U_{out} Uout目标矢量,之前提到了
U α = U m c o s θ U_α = U_mcosθ Uα=Umcosθ
U β = U m s i n θ U_β = U_msinθ Uβ=Umsinθ
那么这里的 U m Um Um就是我们 U r e f U_{ref} Uref

【Q】接下来分析 U m c o s θ = U_mcosθ = Umcosθ= U m s i n θ = U_msinθ = Umsinθ=
【A】根据上图标注 :

  1. U m c o s θ U_mcosθ Umcosθ 为 红线1+红线2,其中红线1可以由U4这个矢量得到,红线2为U6经过cos60°可以得到,这里为什么要分为红线1与红线2,直接cosθ不就可以直接由U4矢量输出完成了吗,答案是因为要考虑后面 U m s i n θ U_msinθ Umsinθ的计算, U m s i n θ U_msinθ Umsinθ以图中加辅助线,可以通过sin60°U6得到 U m s i n θ U_msinθ Umsinθ的结果。

  2. U m s i n θ U_msinθ Umsinθ 为 绿线,刚刚描述了这些线段的意义,以及图中加辅助线的意义,因此通过sin60°U6可以得到 U m s i n θ U_msinθ Umsinθ的结果。

【Q】我们芯片可以输出PWM高分辨率控制开关管,那么怎么把PWM与上面的公式逻辑结合起来?
【A】上面可以100, 110, 010, 011, 001, 101这六个组合分别对应了三组开关管的状态,“1”为上管开启,下管关闭,“0”为下管开启,上管关闭,上下管为互补状态,一个总周期 T s = T x + T y + T n T_s=T_x+T_y+T_n Ts=Tx+Ty+Tn 组成,这里 T x T y T_xT_y TxTy为对应矢量状态PWM输出, T n Tn Tn为不输出的周期,既然TxTy跟基本矢量产生联系,而UαUβ也跟基本矢量产生联系,那么TxTy就能跟UαUβ产生联系,这里也正式进入了SVPWM的计算联系点,接下来把六个矢量状态列出对应PWM(Tx,Ty)对应关系,这里的关系是人为设定的。

TxTy
U4(100)U6(110)
U2(010)U3(011)
U1(001)U5(101)

【Q】矢量的大小怎么确定?
【A】芯片输出的PWM来控制这些状态的占空比就可以实现矢量中的大小

【Q】矢量的方向怎么确定?
【A】这时候就要结合两个矢量的大小来“拉动”输出目标矢量,就像拔河比赛一样,两边谁拉的力多一点,绳子中间就往哪边靠,这里的 “绳子中间“ 就是 矢量合成

搞懂以上逻辑后,就可以计算出 目标矢量 了,而SVPWM之所以成为SVPWM就是因为芯片输出PWM来控制基本矢量状态,从而合成出“空间目标矢量 U o u t U_{out} Uout”。


2.1 扇区Ⅰ计算

在这里插入图片描述
根据上图解析出以下公式 :

U α = U o u t c o s θ = 2 3 U d c ∗ T x T s + 2 3 U d c ∗ T y T s ∗ c o s 60 ° U_α = U_{out}cosθ = \frac23U_{dc}*\frac {T_x} {T_s}+\frac23U_{dc}*\frac {T_y} {T_s}*cos60° Uα=Uoutcosθ=32UdcTsTx+32UdcTsTycos60°

U β = U o u t s i n θ = 2 3 U d c ∗ T y T s ∗ s i n 60 ° U_β = U_{out}sinθ = \frac23U_{dc}*\frac {T_y} {T_s} * sin60° Uβ=Uoutsinθ=32UdcTsTysin60°

可以看出Uα有涉及了Tx与Ty,而Uβ只有Ty,因此我们先求解Uβ中的Ty再代入Uα从而把Tx也求解出来


1. 解析扇区Ⅰ的 T y T_y Ty

U β = U o u t s i n θ = 2 3 U d c ∗ T y T s ∗ s i n 60 ° U_β = U_{out}sinθ = \frac23U_{dc}*\frac {T_y} {T_s} * sin60° Uβ=Uoutsinθ=32UdcTsTysin60°

U β = 2 3 U d c ∗ T y T s ∗ 3 2 U_β = \frac23U_{dc}*\frac {T_y} {T_s} * \frac {\sqrt3}2 Uβ=32UdcTsTy23

U β = 3 3 U d c ∗ T y T s U_β = \frac {\sqrt3}3U_{dc}*\frac {T_y} {T_s} Uβ=33 UdcTsTy

U β = 1 3 U d c ∗ T y T s U_β = \frac 1{\sqrt3}U_{dc}*\frac {T_y} {T_s} Uβ=3 1UdcTsTy

T y = 3 T s U d c U β T_y = \frac {\sqrt3 T_s}{U_{dc}}U_β Ty=Udc3 TsUβ


2. 解析扇区Ⅰ的 T x T_x Tx

U α = U o u t c o s θ = 2 3 U d c ∗ T x T s + 2 3 U d c ∗ T y T s ∗ c o s 60 ° U_α = U_{out}cosθ = \frac23U_{dc}*\frac {T_x} {T_s}+\frac23U_{dc}*\frac {T_y} {T_s}*cos60° Uα=Uoutcosθ=32UdcTsTx+32UdcTsTycos60°

U α = 2 3 U d c ∗ T x T s + 2 3 U d c ∗ T y T s ∗ 1 2 U_α = \frac23U_{dc}*\frac {T_x} {T_s}+\frac23U_{dc}*\frac {T_y} {T_s}*\frac 1 2 Uα=32UdcTsTx+32UdcTsTy21

U α = 2 3 U d c 1 T s ( T x + T y 1 2 ) U_α = \frac23U_{dc}\frac1{T_s}(T_x+T_y\frac12) Uα=32UdcTs1(Tx+Ty21)

T x = U α T s U d c 3 2 − T y 1 2 T_x= \frac {U_αT_s}{U_{dc}} \frac 3 2-T_y\frac12 Tx=UdcUαTs23Ty21

T x = U α T s U d c 3 2 − 3 T s U d c U β 1 2 T_x= \frac {U_αT_s}{U_{dc}} \frac 3 2-\frac {\sqrt3 T_s}{U_{dc}}U_β\frac12 Tx=UdcUαTs23Udc3 TsUβ21

T x = U α T s 3 − 3 T s U β U d c 2 T_x= \frac { U_αT_s3-\sqrt3T_sU_β } {U_{dc}2} Tx=Udc2UαTs33 TsUβ

T x = 3 T s ( U α 3 − U β ) U d c 2 T_x= \frac { \sqrt3T_s(U_α\sqrt3-U_β) } {U_{dc}2} Tx=Udc23 Ts(Uα3 Uβ)

T x = 3 T s U d c ( 3 2 U α − 1 2 U β ) T_x= \frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α-\frac 1 2U_β ) Tx=Udc3 Ts(23 Uα21Uβ)


2.2 扇区Ⅱ计算

在这里插入图片描述

根据上图解析出以下公式 :

U o u t c o s ( θ − 60 ° ) = 2 3 U d c ∗ T y T s + 2 3 U d c ∗ T x T s ∗ c o s 60 ° U_{out}cos(θ-60°) = \frac23U_{dc}*\frac {T_y} {T_s}+\frac23U_{dc}*\frac {T_x} {T_s}*cos60° Uoutcos(θ60°)=32UdcTsTy+32UdcTsTxcos60°

U o u t s i n ( θ − 60 ° ) = 2 3 U d c ∗ T x T s ∗ s i n 60 ° U_{out}sin(θ-60°) = \frac23U_{dc}*\frac {T_x} {T_s} * sin60° Uoutsin(θ60°)=32UdcTsTxsin60°

可以看出Uα有涉及了Tx与Ty,而Uβ只有Tx,因此我们先求解Uβ中的Tx再代入Uα从而把Ty也求解出来
【Q】这里为什么是 θ − 60 ° θ-60° θ60°
【A】因为第二扇区的范围是60-120°,我们计算第二扇区需要偏移60°,从而映射0-60°,从而对应 U α = U o u t c o s θ U_α = U_{out}cosθ Uα=Uoutcosθ U β = U o u t s i n θ U_β = U_{out}sinθ Uβ=Uoutsinθ


1. 解析扇区Ⅱ的 T x T_x Tx

U o u t s i n ( θ − 60 ° ) = 2 3 U d c ∗ T x T s ∗ s i n 60 ° U_{out}sin(θ-60°) = \frac23U_{dc}*\frac {T_x} {T_s} * sin60° Uoutsin(θ60°)=32UdcTsTxsin60°

U o u t s i n ( θ − 60 ° ) = 2 3 U d c ∗ T x T s ∗ 3 2 U_{out}sin(θ-60°) = \frac23U_{dc}*\frac {T_x} {T_s} * \frac {\sqrt3}2 Uoutsin(θ60°)=32UdcTsTx23

U o u t s i n ( θ − 60 ° ) = 1 3 U d c ∗ T x T s U_{out}sin(θ-60°) = \frac 1 {\sqrt3}U_{dc}*\frac {T_x}{T_s} Uoutsin(θ60°)=3 1UdcTsTx

U o u t s i n ( θ − 60 ° ) = 1 3 U d c ∗ T x T s U_{out}sin(θ-60°) = \frac 1 {\sqrt3}U_{dc}*\frac {T_x}{T_s} Uoutsin(θ60°)=3 1UdcTsTx

T x = 3 T s U d c U o u t s i n ( θ − 60 ° ) T_x= \frac {\sqrt3T_s}{U_{dc}}U_{out}sin(θ-60°) Tx=Udc3 TsUoutsin(θ60°)

T x = 3 T s U d c U o u t ( s i n θ c o s 60 ° − c o s θ s i n 60 ° ) T_x= \frac {\sqrt3T_s}{U_{dc}}U_{out}(sinθcos60°-cosθsin60°) Tx=Udc3 TsUout(sinθcos60°cosθsin60°)

T x = 3 T s U d c U o u t ( 1 2 s i n θ − 3 2 c o s θ ) T_x= \frac {\sqrt3T_s}{U_{dc}}U_{out}(\frac12sinθ-\frac{\sqrt3}2cosθ) Tx=Udc3 TsUout(21sinθ23 cosθ)

T x = 3 T s U d c ( − 3 2 U α + 1 2 U β ) T_x=\frac {\sqrt3 T_s}{U_{dc}}( -\frac {\sqrt3}2U_α+\frac 1 2U_β ) Tx=Udc3 Ts(23 Uα+21Uβ)


2. 解析扇区Ⅱ的 T y T_y Ty

U o u t c o s ( θ − 60 ° ) = 2 3 U d c ∗ T y T s + 2 3 U d c ∗ T x T s ∗ c o s 60 ° U_{out}cos(θ-60°) = \frac23U_{dc}*\frac {T_y} {T_s}+\frac23U_{dc}*\frac {T_x} {T_s}*cos60° Uoutcos(θ60°)=32UdcTsTy+32UdcTsTxcos60°

U o u t c o s ( θ − 60 ° ) = 2 3 U d c ∗ T y T s + 2 3 U d c ∗ T x T s ∗ 1 2 U_{out}cos(θ-60°) = \frac23U_{dc}*\frac {T_y} {T_s}+\frac23U_{dc}*\frac {T_x} {T_s}*\frac12 Uoutcos(θ60°)=32UdcTsTy+32UdcTsTx21

U o u t c o s ( θ − 60 ° ) = 2 3 U d c ∗ T y T s + 1 3 U d c ∗ T x T s U_{out}cos(θ-60°) = \frac23U_{dc}*\frac {T_y} {T_s}+\frac13U_{dc}*\frac {T_x} {T_s} Uoutcos(θ60°)=32UdcTsTy+31UdcTsTx

U o u t c o s ( θ − 60 ° ) = 2 3 U d c ∗ T y T s + 1 3 U d c ∗ 3 T s U d c ( − 3 2 U α + 1 2 U β ) T s U_{out}cos(θ-60°) = \frac23U_{dc}*\frac {T_y} {T_s}+\frac13U_{dc}*\frac {\frac {\sqrt3 T_s}{U_{dc}}( -\frac {\sqrt3}2U_α+\frac 1 2U_β )} {T_s} Uoutcos(θ60°)=32UdcTsTy+31UdcTsUdc3 Ts(23 Uα+21Uβ)

U o u t c o s ( θ − 60 ° ) = 2 3 U d c ∗ T y T s − 3 3 ( − 3 2 U α + 1 2 U β ) U_{out}cos(θ-60°) = \frac23U_{dc}*\frac {T_y} {T_s} - \frac{ \sqrt3 }3( -\frac {\sqrt3}2U_α+\frac 1 2U_β ) Uoutcos(θ60°)=32UdcTsTy33 (23 Uα+21Uβ)

T y = U o u t ( c o s θ c o s 60 ° + s i n θ s i n 60 ° ) − 3 3 ( − 3 2 U α + 1 2 U β ) 2 3 U d c T s T_y = \frac {U_{out}(cosθcos60°+sinθsin60°) - \frac{ \sqrt3 }3( -\frac {\sqrt3}2U_α+\frac 1 2U_β ) } {\frac 23U_{dc}}T_s Ty=32UdcUout(cosθcos60°+sinθsin60°)33 (23 Uα+21Uβ)Ts

T y = U α 1 2 + U β 3 2 + 1 2 U α − 3 6 U β 2 3 U d c T s T_y = \frac {Uα\frac12+Uβ\frac{\sqrt3}{2} + \frac 12U_α-\frac {\sqrt3} 6U_β } {\frac 23U_{dc}}T_s Ty=32Udc21+Uβ23 +21Uα63 UβTs

T y = U α + U β 2 3 6 2 3 U d c T s T_y = \frac {Uα+Uβ\frac{2\sqrt3}{6} } {\frac 23U_{dc}}T_s Ty=32Udc+Uβ623 Ts

T y = 3 U α + 3 U β 2 U d c T s T_y = \frac {3Uα+{\sqrt3}Uβ } {2U_{dc}}T_s Ty=2Udc3+3 UβTs

T x = 3 T s U d c ( 3 2 U α + 1 2 U β ) T_x=\frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α+\frac 1 2U_β ) Tx=Udc3 Ts(23 Uα+21Uβ)


2.3 扇区Ⅲ计算

在这里插入图片描述

根据上图解析出以下公式 :

U o u t c o s ( θ − 120 ° ) = 2 3 U d c ∗ T x T s + 2 3 U d c ∗ T y T s ∗ c o s 60 ° U_{out}cos(θ-120°) = \frac23U_{dc}*\frac {T_x} {T_s}+\frac23U_{dc}*\frac {T_y} {T_s}*cos60° Uoutcos(θ120°)=32UdcTsTx+32UdcTsTycos60°

U o u t s i n ( θ − 120 ° ) = 2 3 U d c ∗ T y T s ∗ s i n 60 ° U_{out}sin(θ-120°) = \frac23U_{dc}*\frac {T_y} {T_s} * sin60° Uoutsin(θ120°)=32UdcTsTysin60°

可以看出Uα有涉及了Tx与Ty,而Uβ只有Ty,因此我们先求解Uβ中的Ty再代入Uα从而把Tx也求解出来
【Q】这里为什么是 θ − 120 ° θ-120° θ120°
【A】因为第二扇区的范围是120-180°,我们计算第二扇区需要偏移120°,从而映射0-60°,从而对应 U α = U o u t c o s θ U_α = U_{out}cosθ Uα=Uoutcosθ U β = U o u t s i n θ U_β = U_{out}sinθ Uβ=Uoutsinθ


1. 解析扇区Ⅲ的 T y T_y Ty

U o u t s i n ( θ − 120 ° ) = 2 3 U d c ∗ T y T s ∗ s i n 60 ° U_{out}sin(θ-120°) = \frac23U_{dc}*\frac {T_y} {T_s} * sin60° Uoutsin(θ120°)=32UdcTsTysin60°

U o u t s i n ( θ − 120 ° ) = 2 3 U d c ∗ T y T s ∗ 3 2 U_{out}sin(θ-120°) = \frac23U_{dc}*\frac {T_y} {T_s} * \frac {\sqrt3}2 Uoutsin(θ120°)=32UdcTsTy23

U o u t s i n ( θ − 120 ° ) = 1 3 U d c ∗ T y T s U_{out}sin(θ-120°) = \frac 1 {\sqrt3}U_{dc}*\frac {T_y}{T_s} Uoutsin(θ120°)=3 1UdcTsTy

U o u t s i n ( θ − 120 ° ) = 1 3 U d c ∗ T y T s U_{out}sin(θ-120°) = \frac 1 {\sqrt3}U_{dc}*\frac {T_y}{T_s} Uoutsin(θ120°)=3 1UdcTsTy

T y = 3 T s U d c U o u t s i n ( θ − 120 ° ) T_y= \frac {\sqrt3T_s}{U_{dc}}U_{out}sin(θ-120°) Ty=Udc3 TsUoutsin(θ120°)

T y = 3 T s U d c U o u t ( s i n θ c o s 120 ° − c o s θ s i n 120 ° ) T_y= \frac {\sqrt3T_s}{U_{dc}}U_{out}(sinθcos120°-cosθsin120°) Ty=Udc3 TsUout(sinθcos120°cosθsin120°)

T y = 3 T s U d c U o u t ( − 1 2 s i n θ − 3 2 c o s θ ) T_y= \frac {\sqrt3T_s}{U_{dc}}U_{out}(-\frac12sinθ-\frac{\sqrt3}2cosθ) Ty=Udc3 TsUout(21sinθ23 cosθ)

T y = − 3 T s U d c ( 3 2 U α + 1 2 U β ) T_y=-\frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α+\frac 1 2U_β ) Ty=Udc3 Ts(23 Uα+21Uβ)


2. 解析扇区Ⅲ的 T x T_x Tx

U o u t c o s ( θ − 120 ° ) = 2 3 U d c ∗ T x T s + 2 3 U d c ∗ T y T s ∗ c o s 60 ° U_{out}cos(θ-120°) = \frac23U_{dc}*\frac {T_x} {T_s}+\frac23U_{dc}*\frac {T_y} {T_s}*cos60° Uoutcos(θ120°)=32UdcTsTx+32UdcTsTycos60°

U o u t c o s ( θ − 120 ° ) = 2 3 U d c ∗ T x T s + 2 3 U d c ∗ T y T s ∗ 1 2 U_{out}cos(θ-120°) = \frac23U_{dc}*\frac {T_x} {T_s}+\frac23U_{dc}*\frac {T_y} {T_s}*\frac12 Uoutcos(θ120°)=32UdcTsTx+32UdcTsTy21

U o u t c o s ( θ − 120 ° ) = 2 3 U d c ∗ T x T s + 1 3 U d c ∗ T y T s U_{out}cos(θ-120°) = \frac23U_{dc}*\frac {T_x} {T_s}+\frac13U_{dc}*\frac {T_y} {T_s} Uoutcos(θ120°)=32UdcTsTx+31UdcTsTy

U o u t c o s ( θ − 120 ° ) = 2 3 U d c ∗ T x T s + 1 3 U d c ∗ − 3 T s U d c ( 3 2 U α + 1 2 U β ) T s U_{out}cos(θ-120°) = \frac23U_{dc}*\frac {Tx} {T_s}+\frac13U_{dc}*\frac {-\frac {\sqrt3 T_s}{U_{dc}}( \frac {\sqrt3}2U_α+\frac 1 2U_β )} {T_s} Uoutcos(θ120°)=32UdcTsTx+31UdcTsUdc3 Ts(23 Uα+21Uβ)

U o u t c o s ( θ − 120 ° ) = 2 3 U d c ∗ T x T s − 3 3 ( 3 2 U α + 1 2 U β ) U_{out}cos(θ-120°) = \frac23U_{dc}*\frac {T_x} {T_s} - \frac{ \sqrt3 }3( \frac {\sqrt3}2U_α+\frac 1 2U_β ) Uoutcos(θ120°)=32UdcTsTx33 (23 Uα+21Uβ)

T x = U o u t ( c o s θ c o s 120 ° + s i n θ s i n 120 ° ) + 3 3 ( 3 2 U α + 1 2 U β ) 2 3 U d c T s T_x = \frac {U_{out}(cosθcos120°+sinθsin120°) + \frac{ \sqrt3 }3( \frac {\sqrt3}2U_α+\frac 1 2U_β ) } {\frac 23U_{dc}}T_s Tx=32UdcUout(cosθcos120°+sinθsin120°)+33 (23 Uα+21Uβ)Ts

T x = − 1 2 U α + 3 2 U β + 1 2 U α + 3 6 U β 2 3 U d c T s T_x = \frac {-\frac12Uα+\frac{\sqrt3}{2}Uβ + \frac 12U_α+\frac {\sqrt3} 6U_β } {\frac 23U_{dc}}T_s Tx=32Udc21+23 Uβ+21Uα+63 UβTs

T x = U β 2 3 3 2 3 U d c T s T_x = \frac {Uβ\frac{2\sqrt3}{3} } {\frac 23U_{dc}}T_s Tx=32UdcUβ323 Ts

T x = 3 T s U d c U β T_x = \frac {\sqrt3 T_s}{U_{dc}}Uβ Tx=Udc3 TsUβ


由于手敲公式占了太多字数空间,超出编辑字数,因此扇区计算分为两篇,扇区4,5,6计算可通过下方链接进入

[嵌入式专栏](FOC - SVPWM扇区计算Part2)

3 . 小结

计算出了SVPWM每个扇区的Tx与Ty就可以进行扇区输出了,下一篇讲解扇区输出调整,谢谢观看。

技术交流QQ群 : 745662457
群内专注 - 问题答疑,技术研究

图片资源本人在网上下载,若有侵权行为,请告知,本人会立刻删除

#include "MyProject.h" #include "DRV8313.h" #include "BLDC_tim.h" #include "tim.h" /************************************************ main中调用的接口函数都在当前文件中 ================================================= 本程序仅供学习,引用代码请标明出处 使用教程:https://blog.youkuaiyun.com/loop222/article/details/120471390 创建日期:20210925 作 者:loop222 @郑州 ************************************************/ /******************************************************************************/ extern float target; /******************************************************************************/ long sensor_direction; float voltage_power_supply; float voltage_limit; float voltage_sensor_align; int pole_pairs; unsigned long open_loop_timestamp; float velocity_limit; /******************************************************************************/ int alignSensor(void); float velocityOpenloop(float target_velocity); float angleOpenloop(float target_angle); /******************************************************************************/ void Motor_init(void) { // printf("MOT: Init\r\n"); // new_voltage_limit = current_limit * phase_resistance; // voltage_limit = new_voltage_limit < voltage_limit ? new_voltage_limit : voltage_limit; if(voltage_sensor_align > voltage_limit) voltage_sensor_align = voltage_limit; sensor_direction=UNKNOWN; //M1_Enable; // printf("MOT: Enable driver.\r\n"); } /******************************************************************************/ void Motor_initFOC(void) { alignSensor(); //检测零点偏移量和极对数 //added the shaft_angle update angle_prev=getAngle(); //getVelocity(),make sure velocity=0 after power on HAL_Delay(5); shaft_velocity = shaftVelocity(); //必须调用一次,进入主循环后速度为0 HAL_Delay(5); shaft_angle = shaftAngle();// shaft angle if(controller==Type_angle)target=shaft_angle;//角度模式,以当前的角度为目标角度,进入主循环后电机静止 HAL_Delay(200); } /******************************************************************************/ int alignSensor(void) { long i; float angle; float mid_angle,end_angle; float moved; // printf("MOT: Align sensor.\r\n"); // find natural direction // move one electrical revolution forward for(i=0; i<=500; i++) { angle = _3PI_2 + _2PI * i / 500.0; setPhaseVoltage(voltage_sensor_align, 0, angle); HAL_Delay(2); } mid_angle=getAngle(); for(i=500; i>=0; i--) { angle = _3PI_2 + _2PI * i / 500.0 ; setPhaseVoltage(voltage_sensor_align, 0, angle); HAL_Delay(2); } end_angle=getAngle(); setPhaseVoltage(0, 0, 0); HAL_Delay(200); // printf("mid_angle=%.4f\r\n",mid_angle); // printf("end_angle=%.4f\r\n",end_angle); moved = fabs(mid_angle - end_angle); if((mid_angle == end_angle)||(moved < 0.02)) //相等或者几乎没有动 { // printf("MOT: Failed to notice movement loop222.\r\n"); // M1_Disable; //电机检测不正常,关闭驱动 DRV8313_ENx_Off(); return 0; } else if(mid_angle < end_angle) { // printf("MOT: sensor_direction==CCW\r\n"); sensor_direction=CCW; } else { // printf("MOT: sensor_direction==CW\r\n"); sensor_direction=CW; } // printf("MOT: PP check: "); //计算Pole_Pairs if( fabs(moved*pole_pairs - _2PI) > 0.5 ) // 0.5 is arbitrary number it can be lower or higher! { // printf("fail - estimated pp:"); pole_pairs=_2PI/moved+0.5; //浮点数转整形,四舍五入 // printf("%d\r\n",pole_pairs); } else // printf("OK!\r\n"); setPhaseVoltage(voltage_sensor_align, 0, _3PI_2); //计算零点偏移角度 HAL_Delay(700); zero_electric_angle = _normalizeAngle(_electricalAngle(sensor_direction*getAngle(), pole_pairs)); HAL_Delay(20); // printf("MOT: Zero elec. angle:"); // printf("%.4f\r\n",zero_electric_angle); setPhaseVoltage(0, 0, 0); // delay_ms(200); return 1; } /******************************************************************************/ void loopFOC(void) { if( controller==Type_angle_openloop || controller==Type_velocity_openloop ) return; shaft_angle = shaftAngle();// shaft angle electrical_angle = electricalAngle();// electrical angle - need shaftAngle to be called first switch(torque_controller) { case Type_voltage: // no need to do anything really break; case Type_dc_current: break; case Type_foc_current: break; default: // printf("MOT: no torque control selected!"); break; } // set the phase voltage - FOC heart function :) setPhaseVoltage(voltage.q, voltage.d, electrical_angle); } /******************************************************************************/ void move(float new_target) { shaft_velocity = shaftVelocity(); switch(controller) { case Type_torque: if(torque_controller==Type_voltage)voltage.q = new_target; // if voltage torque control else current_sp = new_target; // if current/foc_current torque control break; case Type_angle: // angle set point shaft_angle_sp = new_target; // calculate velocity set point shaft_velocity_sp = PID_angle( shaft_angle_sp - shaft_angle ); // calculate the torque command current_sp = PID_velocity(shaft_velocity_sp - shaft_velocity); // if voltage torque control // if torque controlled through voltage if(torque_controller == Type_voltage) { voltage.q = current_sp; voltage.d = 0; } break; case Type_velocity: // velocity set point shaft_velocity_sp = new_target; // calculate the torque command current_sp = PID_velocity(shaft_velocity_sp - shaft_velocity); // if current/foc_current torque control // if torque controlled through voltage control if(torque_controller == Type_voltage) { voltage.q = current_sp; // use voltage if phase-resistance not provided voltage.d = 0; } break; case Type_velocity_openloop: // velocity control in open loop shaft_velocity_sp = new_target; voltage.q = velocityOpenloop(shaft_velocity_sp); // returns the voltage that is set to the motor voltage.d = 0; break; case Type_angle_openloop: // angle control in open loop shaft_angle_sp = new_target; voltage.q = angleOpenloop(shaft_angle_sp); // returns the voltage that is set to the motor voltage.d = 0; break; } } /******************************************************************************/ void setPhaseVoltage(float Uq, float Ud, float angle_el) { float Uout; uint32_t sector; float T0,T1,T2; float Ta,Tb,Tc; if(Ud) // only if Ud and Uq set {// _sqrt is an approx of sqrt (3-4% error) Uout = _sqrt(Ud*Ud + Uq*Uq) / voltage_power_supply; // angle normalisation in between 0 and 2pi // only necessary if using _sin and _cos - approximation functions angle_el = _normalizeAngle(angle_el + atan2(Uq, Ud)); } else {// only Uq available - no need for atan2 and sqrt Uout = Uq / voltage_power_supply; // angle normalisation in between 0 and 2pi // only necessary if using _sin and _cos - approximation functions angle_el = _normalizeAngle(angle_el + _PI_2); } if(Uout> 0.577)Uout= 0.577; if(Uout<-0.577)Uout=-0.577; sector = (angle_el / _PI_3) + 1; T1 = _SQRT3*_sin(sector*_PI_3 - angle_el) * Uout; T2 = _SQRT3*_sin(angle_el - (sector-1.0)*_PI_3) * Uout; T0 = 1 - T1 - T2; // calculate the duty cycles(times) switch(sector) { case 1: Ta = T1 + T2 + T0/2; Tb = T2 + T0/2; Tc = T0/2; break; case 2: Ta = T1 + T0/2; Tb = T1 + T2 + T0/2; Tc = T0/2; break; case 3: Ta = T0/2; Tb = T1 + T2 + T0/2; Tc = T2 + T0/2; break; case 4: Ta = T0/2; Tb = T1+ T0/2; Tc = T1 + T2 + T0/2; break; case 5: Ta = T2 + T0/2; Tb = T0/2; Tc = T1 + T2 + T0/2; break; case 6: Ta = T1 + T2 + T0/2; Tb = T0/2; Tc = T1 + T0/2; break; default: // possible error state Ta = 0; Tb = 0; Tc = 0; } SetPWMDutyPersent(&htim3, TIM_CHANNEL_1, Ta*100); SetPWMDutyPersent(&htim3, TIM_CHANNEL_2, Tb*100); SetPWMDutyPersent(&htim3, TIM_CHANNEL_3, Tc*100); // TIM_SetCompare1(TIM2,Ta*PWM_Period); // TIM_SetCompare2(TIM2,Tb*PWM_Period); // TIM_SetCompare3(TIM2,Tc*PWM_Period); } /******************************************************************************/ float velocityOpenloop(float target_velocity) { unsigned long now_us; float Ts,Uq; now_us = SysTick->VAL; //_micros(); if(now_us<open_loop_timestamp)Ts = (float)(open_loop_timestamp - now_us)/9*1e-6; else Ts = (float)(0xFFFFFF - now_us + open_loop_timestamp)/9*1e-6; open_loop_timestamp=now_us; //save timestamp for next call // quick fix for strange cases (micros overflow) if(Ts == 0 || Ts > 0.5) Ts = 1e-3; // calculate the necessary angle to achieve target velocity shaft_angle = _normalizeAngle(shaft_angle + target_velocity*Ts); Uq = voltage_limit; // set the maximal allowed voltage (voltage_limit) with the necessary angle setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, pole_pairs)); return Uq; } /******************************************************************************/ float angleOpenloop(float target_angle) { unsigned long now_us; float Ts,Uq; now_us = SysTick->VAL; //_micros(); if(now_us<open_loop_timestamp)Ts = (float)(open_loop_timestamp - now_us)/9*1e-6; else Ts = (float)(0xFFFFFF - now_us + open_loop_timestamp)/9*1e-6; open_loop_timestamp = now_us; //save timestamp for next call // quick fix for strange cases (micros overflow) if(Ts == 0 || Ts > 0.5) Ts = 1e-3; // calculate the necessary angle to move from current position towards target angle // with maximal velocity (velocity_limit) if(fabs( target_angle - shaft_angle ) > velocity_limit*Ts) { shaft_angle += _sign(target_angle - shaft_angle) * velocity_limit * Ts; //shaft_velocity = velocity_limit; } else { shaft_angle = target_angle; //shaft_velocity = 0; } Uq = voltage_limit; // set the maximal allowed voltage (voltage_limit) with the necessary angle setPhaseVoltage(Uq, 0, _electricalAngle(shaft_angle, pole_pairs)); return Uq; } /******************************************************************************/ #include "MyProject.h" /***************************************************************************/ // int array instead of float array // 4x200 points per 360 deg // 2x storage save (int 2Byte float 4 Byte ) // sin*10000 const int sine_array[200] = {0,79,158,237,316,395,473,552,631,710,789,867,946,1024,1103,1181,1260,1338,1416,1494,1572,1650,1728,1806,1883,1961,2038,2115,2192,2269,2346,2423,2499,2575,2652,2728,2804,2879,2955,3030,3105,3180,3255,3329,3404,3478,3552,3625,3699,3772,3845,3918,3990,4063,4135,4206,4278,4349,4420,4491,4561,4631,4701,4770,4840,4909,4977,5046,5113,5181,5249,5316,5382,5449,5515,5580,5646,5711,5775,5839,5903,5967,6030,6093,6155,6217,6279,6340,6401,6461,6521,6581,6640,6699,6758,6815,6873,6930,6987,7043,7099,7154,7209,7264,7318,7371,7424,7477,7529,7581,7632,7683,7733,7783,7832,7881,7930,7977,8025,8072,8118,8164,8209,8254,8298,8342,8385,8428,8470,8512,8553,8594,8634,8673,8712,8751,8789,8826,8863,8899,8935,8970,9005,9039,9072,9105,9138,9169,9201,9231,9261,9291,9320,9348,9376,9403,9429,9455,9481,9506,9530,9554,9577,9599,9621,9642,9663,9683,9702,9721,9739,9757,9774,9790,9806,9821,9836,9850,9863,9876,9888,9899,9910,9920,9930,9939,9947,9955,9962,9969,9975,9980,9985,9989,9992,9995,9997,9999,10000,10000}; /***************************************************************************/ // function approximating the sine calculation by using fixed size array // ~40us (float array) // ~50us (int array) // precision +-0.005 // it has to receive an angle in between 0 and 2PI float _sin(float a){ if(a < _PI_2){ //return sine_array[(int)(199.0*( a / (_PI/2.0)))]; //return sine_array[(int)(126.6873* a)]; // float array optimized return 0.0001*sine_array[_round(126.6873* a)]; // int array optimized }else if(a < _PI){ // return sine_array[(int)(199.0*(1.0 - (a-_PI/2.0) / (_PI/2.0)))]; //return sine_array[398 - (int)(126.6873*a)]; // float array optimized return 0.0001*sine_array[398 - _round(126.6873*a)]; // int array optimized }else if(a < _3PI_2){ // return -sine_array[(int)(199.0*((a - _PI) / (_PI/2.0)))]; //return -sine_array[-398 + (int)(126.6873*a)]; // float array optimized return -0.0001*sine_array[-398 + _round(126.6873*a)]; // int array optimized } else { // return -sine_array[(int)(199.0*(1.0 - (a - 3*_PI/2) / (_PI/2.0)))]; //return -sine_array[796 - (int)(126.6873*a)]; // float array optimized return -0.0001*sine_array[796 - _round(126.6873*a)]; // int array optimized } } /***************************************************************************/ // function approximating cosine calculation by using fixed size array // ~55us (float array) // ~56us (int array) // precision +-0.005 // it has to receive an angle in between 0 and 2PI float _cos(float a){ float a_sin = a + _PI_2; a_sin = a_sin > _2PI ? a_sin - _2PI : a_sin; return _sin(a_sin); } /***************************************************************************/ // normalizing radian angle to [0,2PI] float _normalizeAngle(float angle){ float a = fmod(angle, _2PI); return a >= 0 ? a : (a + _2PI); } /***************************************************************************/ // Electrical angle calculation float _electricalAngle(float shaft_angle, int pole_pairs) { return (shaft_angle * pole_pairs); } /***************************************************************************/ // square root approximation function using // https://reprap.org/forum/read.php?147,219210 // https://en.wikipedia.org/wiki/Fast_inverse_square_root float _sqrtApprox(float number) {//low in fat long i; float y; // float x; // const float f = 1.5F; // better precision // x = number * 0.5F; y = number; i = * ( long * ) &y; i = 0x5f375a86 - ( i >> 1 ); y = * ( float * ) &i; // y = y * ( f - ( x * y * y ) ); // better precision return number * y; } /***************************************************************************/ #include "MyProject.h" /******************************************************************************/ float shaft_angle;//!< current motor angle float electrical_angle; float shaft_velocity; float current_sp; float shaft_velocity_sp; float shaft_angle_sp; DQVoltage_s voltage; DQCurrent_s current; TorqueControlType torque_controller; MotionControlType controller; float sensor_offset=0; float zero_electric_angle; /******************************************************************************/ // shaft angle calculation float shaftAngle(void) { // if no sensor linked return previous value ( for open loop ) //if(!sensor) return shaft_angle; return sensor_direction*getAngle() - sensor_offset; } // shaft velocity calculation float shaftVelocity(void) { // if no sensor linked return previous value ( for open loop ) //if(!sensor) return shaft_velocity; return sensor_direction*LPF_velocity(getVelocity()); } /******************************************************************************/ float electricalAngle(void) { return _normalizeAngle((shaft_angle + sensor_offset) * pole_pairs - zero_electric_angle); } /******************************************************************************/ #include "MyProject.h" /******************************************************************************/ #define DEF_CURR_FILTER_Tf 0.005 //!< default currnet filter time constant #define DEF_VEL_FILTER_Tf 0.005 //!< default velocity filter time constant /******************************************************************************/ //unsigned long lpf_vel_timestamp; float y_vel_prev=0; /******************************************************************************/ /* float LPF_velocity(float x) { unsigned long now_us; float Ts, alpha, y; now_us = SysTick->VAL; if(now_us<lpf_vel_timestamp)Ts = (float)(lpf_vel_timestamp - now_us)/9*1e-6f; else Ts = (float)(0xFFFFFF - now_us + lpf_vel_timestamp)/9*1e-6f; lpf_vel_timestamp = now_us; if(Ts == 0 || Ts > 0.5) Ts = 1e-3f; alpha = DEF_VEL_FILTER_Tf/(DEF_VEL_FILTER_Tf + Ts); y = alpha*y_prev + (1.0f - alpha)*x; y_prev = y; return y; } */ float LPF_velocity(float x) { float y = 0.9*y_vel_prev + 0.1*x; y_vel_prev=y; return y; } /******************************************************************************/ #include "MyProject.h" #include "AS5600.h" #define AS5600_RAW_ANGLE_REG 0x0C #define AS5600_ANGLE_REG 0x0E /************************************************ 本程序仅供学习,引用代码请标明出处 使用教程:https://blog.youkuaiyun.com/loop222/article/details/120471390 创建日期:20210925 作 者:loop222 @郑州 ************************************************/ /******************************************************************************/ long cpr=4096; float full_rotation_offset; long angle_data_prev; unsigned long velocity_calc_timestamp; float angle_prev; /******************************************************************************/ /******************************************************************************/ void MagneticSensor_Init(void) { angle_data_prev = AS5600_Read_uint16(AS5600_ANGLE_REG); full_rotation_offset = 0; velocity_calc_timestamp=0; } /******************************************************************************/ float getAngle(void) { float angle_data,d_angle; //angle_data = I2C_getRawCount(I2C1); angle_data = AS5600_Read_uint16(AS5600_ANGLE_REG); // tracking the number of rotations // in order to expand angle range form [0,2PI] to basically infinity d_angle = angle_data - angle_data_prev; // if overflow happened track it as full rotation if(fabs(d_angle) > (0.8*cpr) ) full_rotation_offset += d_angle > 0 ? -_2PI : _2PI; // save the current angle value for the next steps // in order to know if overflow happened angle_data_prev = angle_data; // return the full angle // (number of full rotations)*2PI + current sensor angle return (full_rotation_offset + ( angle_data / (float)cpr) * _2PI) ; /* AS5600_Refresh_Angle(&has5600); return has5600.angle;*/ } /******************************************************************************/ // Shaft velocity calculation float getVelocity(void) { unsigned long now_us; float Ts, angle_c, vel; // calculate sample time now_us = SysTick->VAL; //_micros(); if(now_us<velocity_calc_timestamp)Ts = (float)(velocity_calc_timestamp - now_us)/9*1e-6; else Ts = (float)(0xFFFFFF - now_us + velocity_calc_timestamp)/9*1e-6; // quick fix for strange cases (micros overflow) if(Ts == 0 || Ts > 0.5) Ts = 1e-3; // current angle angle_c = getAngle(); // velocity calculation vel = (angle_c - angle_prev)/Ts; // save variables for future pass angle_prev = angle_c; velocity_calc_timestamp = now_us; return vel; } /******************************************************************************/ #include "MyProject.h" /************************************************ 本程序仅供学习,引用代码请标明出处 使用教程:https://blog.youkuaiyun.com/loop222/article/details/120471390 创建日期:20210925 作 者:loop222 @郑州 ************************************************/ /******************************************************************************/ float pid_vel_P, pid_ang_P; float pid_vel_I, pid_ang_D; float integral_vel_prev; float error_vel_prev, error_ang_prev; float output_vel_ramp; float output_vel_prev; unsigned long pid_vel_timestamp, pid_ang_timestamp; /******************************************************************************/ void PID_init(void) { pid_vel_P=0.1; //0.1 pid_vel_I=2; //2 output_vel_ramp=100; //output derivative limit [volts/second] integral_vel_prev=0; error_vel_prev=0; output_vel_prev=0; pid_vel_timestamp=SysTick->VAL; pid_ang_P=10; pid_ang_D=0.5; error_ang_prev=0; pid_ang_timestamp=SysTick->VAL; } /******************************************************************************/ //just P&I is enough,no need D float PID_velocity(float error) { unsigned long now_us; float Ts; float proportional,integral,output; float output_rate; now_us = SysTick->VAL; if(now_us<pid_vel_timestamp)Ts = (float)(pid_vel_timestamp - now_us)/9*1e-6f; else Ts = (float)(0xFFFFFF - now_us + pid_vel_timestamp)/9*1e-6f; pid_vel_timestamp = now_us; if(Ts == 0 || Ts > 0.5) Ts = 1e-3f; // u(s) = (P + I/s + Ds)e(s) // Discrete implementations // proportional part // u_p = P *e(k) proportional = pid_vel_P * error; // Tustin transform of the integral part // u_ik = u_ik_1 + I*Ts/2*(ek + ek_1) integral = integral_vel_prev + pid_vel_I*Ts*0.5*(error + error_vel_prev); // antiwindup - limit the output integral = _constrain(integral, -voltage_limit, voltage_limit); // sum all the components output = proportional + integral; // antiwindup - limit the output variable output = _constrain(output, -voltage_limit, voltage_limit); // limit the acceleration by ramping the output output_rate = (output - output_vel_prev)/Ts; if(output_rate > output_vel_ramp)output = output_vel_prev + output_vel_ramp*Ts; else if(output_rate < -output_vel_ramp)output = output_vel_prev - output_vel_ramp*Ts; // saving for the next pass integral_vel_prev = integral; output_vel_prev = output; error_vel_prev = error; return output; } /******************************************************************************/ //P&D for angle_PID float PID_angle(float error) { unsigned long now_us; float Ts; float proportional,derivative,output; //float output_rate; now_us = SysTick->VAL; if(now_us<pid_ang_timestamp)Ts = (float)(pid_ang_timestamp - now_us)/9*1e-6f; else Ts = (float)(0xFFFFFF - now_us + pid_ang_timestamp)/9*1e-6f; pid_ang_timestamp = now_us; if(Ts == 0 || Ts > 0.5) Ts = 1e-3f; // u(s) = (P + I/s + Ds)e(s) // Discrete implementations // proportional part // u_p = P *e(k) proportional = pid_ang_P * error; // u_dk = D(ek - ek_1)/Ts derivative = pid_ang_D*(error - error_ang_prev)/Ts; output = proportional + derivative; output = _constrain(output, -velocity_limit, velocity_limit); // limit the acceleration by ramping the output // output_rate = (output - output_ang_prev)/Ts; // if(output_rate > output_ang_ramp)output = output_ang_prev + output_ang_ramp*Ts; // else if(output_rate < -output_ang_ramp)output = output_ang_prev - output_ang_ramp*Ts; // saving for the next pass // output_ang_prev = output; error_ang_prev = error; return output; } /******************************************************************************/ /******************************************************************************/ 逐行解释
最新发布
07-23
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客 - L U

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值