文中有部分公式了图片转换失败了,原文是用语雀文档写的,需要的自行下载PDF下载链接或者浏览原文链接:
pdf链接: FOC笔记整理
语雀文档链接: FOC笔记整理
以下是文中一页的截图:
以下是FOC控制框图:
1、Clark变换
所谓克拉克变换,实际上就是降维解耦的过程,把难以辨明和控制的三相相位差120°电机波形降维为两维矢量。
1.1 数学推导
首先因为由基尔霍夫电流定律(KCL),在任一时刻,流入节点的电流之和等于流出节点的电流之和,也就是说
I
a
+
I
b
+
I
c
=
0
I_a+I_b+I_c=0
Ia+Ib+Ic=0
由上图三维变换为二维的变换公式:
{
I
α
=
k
(
I
a
−
I
b
s
i
n
30
°
−
I
c
s
i
n
30
)
I
β
=
k
(
I
b
s
i
n
60
°
−
I
c
s
i
n
60
°
)
⇒
{
I
α
=
k
(
I
a
−
I
b
2
−
I
c
2
)
I
β
=
k
(
3
2
I
b
−
3
2
I
c
)
\left \{ \begin{array}{c} I_\alpha=k(I_a-I_bsin30°-I_csin30) \\ I_\beta=k(I_bsin60°-I_csin60°) \end{array} \right. \Rightarrow \left \{ \begin{array}{c} I_\alpha=k(I_a-\frac{I_b}{2}-\frac{I_c}{2}) \\ I_\beta=k(\frac{\sqrt {3}}{2}I_b-\frac{\sqrt {3}}{2}I_c) \end{array} \right.
{Iα=k(Ia−Ibsin30°−Icsin30)Iβ=k(Ibsin60°−Icsin60°)⇒{Iα=k(Ia−2Ib−2Ic)Iβ=k(23Ib−23Ic)
{
I
α
=
k
(
I
a
−
I
b
2
−
I
c
2
)
I
β
=
k
(
3
2
I
b
−
3
2
I
c
)
I
c
=
−
I
a
−
I
b
⇒
{
I
α
=
k
3
2
I
a
I
β
=
3
k
2
(
I
a
+
2
I
b
)
\left \{ \begin{array}{c} I_\alpha=k(I_a-\frac{I_b}{2}-\frac{I_c}{2}) \\ I_\beta=k(\frac{\sqrt {3}}{2}I_b-\frac{\sqrt {3}}{2}I_c) \\ I_c=-I_a-I_b \end{array} \right. \Rightarrow \left \{ \begin{array}{c} I_\alpha=k\frac{3}{2} I_a\\ I_\beta=\frac{\sqrt {3}k}{2}(I_a+2I_b) \end{array} \right.
⎩
⎨
⎧Iα=k(Ia−2Ib−2Ic)Iβ=k(23Ib−23Ic)Ic=−Ia−Ib⇒{Iα=k23IaIβ=23k(Ia+2Ib)
k
k
k是变换系数,有等幅值变换何恒功率变换
等幅值变换:
k
=
2
3
k=\frac{2}{3}
k=32
恒功率变换:
k
=
2
3
k=\sqrt{\frac{2}{3}}
k=32
1.2 等幅值变换系数
假设变换前
I
a
=
1
,
I
b
=
−
0.5
,
I
c
=
−
0.5
I_a=1,I_b=-0.5,I_c=-0.5
Ia=1,Ib=−0.5,Ic=−0.5
变换后
I
α
=
k
3
2
I
a
=
k
3
2
×
1
=
k
3
2
I_\alpha=k\frac{3}{2} I_a=k\frac{3}{2}\times1=k\frac{3}{2}
Iα=k23Ia=k23×1=k23
前后幅值相等于是
k
3
2
=
1
⇒
k
=
2
3
k\frac{3}{2}=1 \Rightarrow k=\frac{2}{3}
k23=1⇒k=32
1.3 恒功率变换系数
假设变换前
I
a
=
1
,
I
b
=
−
0.5
,
I
c
=
−
0.5
I_a=1,I_b=-0.5,I_c=-0.5
Ia=1,Ib=−0.5,Ic=−0.5
P
=
I
a
2
R
+
I
b
2
R
+
I
c
2
R
=
3
2
R
,
(
R
为相阻抗)
P=I_a^2R+I_b^2R+I_c^2R=\frac{3}{2}R,(R为相阻抗)
P=Ia2R+Ib2R+Ic2R=23R,(R为相阻抗)
变换后
I
α
=
k
3
2
I
a
=
k
3
2
×
1
=
k
3
2
,
I
β
=
3
k
2
(
I
a
+
2
I
b
)
=
0
I_\alpha=k\frac{3}{2} I_a=k\frac{3}{2}\times1=k\frac{3}{2},I_\beta=\frac{\sqrt {3}k}{2}(I_a+2I_b)=0
Iα=k23Ia=k23×1=k23,Iβ=23k(Ia+2Ib)=0
P
=
I
α
2
R
+
I
β
2
R
=
9
4
k
2
R
P=I_\alpha^2R+I_\beta^2R=\frac{9}{4}k^2R
P=Iα2R+Iβ2R=49k2R
前后幅值相等于是
3
2
R
=
9
4
k
2
R
⇒
k
=
2
3
\frac{3}{2}R=\frac{9}{4}k^2R \Rightarrow k=\sqrt{\frac{2}{3}}
23R=49k2R⇒k=32
实际FOC设计中我们一般采用等幅值变换,因为在SVPWM设计中假如采用等功率变换,得到的矢量
U
t
U_t
Ut为相电压峰值的1.5倍,将会超出空间矢量的圆圈,产生过调制。
于是最终变换公式为:
KaTeX parse error: \tag works only in display equations
上式消掉了
I
c
I_c
Ic,这样在设计采样电路时就只需要采集A相和B相的电流就可以了,减少成本和复杂度。
1.4 程序实现
alphaBeta_t Clark(abc_t input)
{
alphaBeta_t output;
output.i_alpha=input.ia; //I_alpha=Ia
output.i_beta=(input.ia+2*input.ib)*0.577350269; //I_beta=(Ia+2Ib)/sqrt(3)
return output;
}
2、Park变换
在Clark变换中,对ABC三维坐标系进行降维处理,但
α
−
β
\alpha-\beta
α−β依然是非线性的,依然很难处理,Park变换就是对
α
−
β
\alpha-\beta
α−β进行线性化处理的过程。在Park变换过程中,把旋转的
d
−
q
d-q
d−q轴作为参考坐标系,实际上对于转子来说,
d
−
q
d-q
d−q坐标系就是静止的坐标系,且
i
d
i_d
id和
i
q
i_q
iq幅值是固定值,于是
d
−
q
d-q
d−q轴呈现出来的效果就是直线(线性化),如下图。角度
θ
\theta
θ就是转子当前旋转的电角度。
2.1 数学推导
由上图可得:
KaTeX parse error: \tag works only in display equations
2.2 程序实现
dq_t Park(alphaBeta_t input,int16_t theta)
{
dq_t output;
Trig_Components TempSinCos;
float cos_da,sin_da;
float I_alpha_ratio,I_beta_ratio;
TempSinCos = Trig_Functions(theta); //get sin_cos value
cos_da = (float)(TempSinCos.hCos*DIV_Q15); //sin_cos is 0-32768 or -32768-0,sin_cos/32768 is 0-1
sin_da = (float)(TempSinCos.hSin*DIV_Q15); //sin_cos is 0-32768 or -32768-0,sin_cos/32768 is 0-1
output.id = input.i_alpha*cos_da + input.i_beta*sin_da;
output.iq = -input.i_alpha*sin_da + input.i_beta*cos_da;
return ( output );
}
3、Park逆变换
Park逆变换其实就是将PI控制器调整后的 I d I_d Id和 I q I_q Iq从 d − q d-q d−q轴转换到 α − β \alpha-\beta α−β轴。
3.1 数学推导
此为正方形矩阵它的逆矩阵则为:($$
ψ
=
θ
\psi =\theta
ψ=θ)
因此Park的逆变换公式如下:
3.2 程序实现
alphaBeta_t Rev_Park(dq_t input,int16_t theta)
{
alphaBeta_t output;
Trig_Components TempSinCos;
float cos_da,sin_da;
float I_alpha_ratio,I_beta_ratio;
TempSinCos = Trig_Functions(theta); //get sin_cos value
cos_da = (float)(TempSinCos.hCos*DIV_Q15); //sin_cos is 0-32768 or -32768-0,sin_cos/32768 is 0-1
sin_da = (float)(TempSinCos.hSin*DIV_Q15); //sin_cos is 0-32768 or -32768-0,sin_cos/32768 is 0-1
output.i_alpha = input.id*cos_da - input.iq*sin_da;
output.i_beta = input.id*sin_da + input.iq*cos_da;
return ( output );
}
4、SVPWM技术
4.1 原理
** SVPWM 的理论基础是平均值等效原理**,即在一个开关周期内通过对基本电压矢量加以组合,使其平均值与给定电压矢量相等。在某个时刻,电压矢量旋转到 某个区域中,可由组成这个区域的两个相邻的非零矢量和零矢量在时间上的不同 组合来得到。两个矢量的作用时间在一个采样周期内分多次施加,从而控制各个 电压矢量的作用时间,使电压空间矢量接近按圆轨迹旋转,通过逆变器的不同开关状态所产生的实际磁通去逼近理想磁通圆,并由两者的比较结果来决定逆变器 的开关状态,从而形成 PWM 波形。
使用这6个空间电压矢量作为基向量来合成任意矢量。在每一个扇区,选择相邻两个电压矢量以及零矢量,按照伏秒平衡原则来合成每个扇区内的任意电压矢量,即:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OdoJR3ES-1687592100934)(null#clientId=u31621085-f95b-4&from=paste&id=u08c5fa00&originHeight=60&originWidth=483&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u7896028c-0ae2-4d23-ad16-2903d69d3d3&title=)]
离散化后等效为下式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-34d6yfMq-1687592100417)(null#clientId=u31621085-f95b-4&from=paste&id=u25a6ab92&originHeight=26&originWidth=336&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u036a431e-2fb7-4c86-a176-a2778d6945c&title=)]
式子中的 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GMw6aQng-1687592101297)(null#clientId=u31621085-f95b-4&from=paste&id=udf58ac18&originHeight=26&originWidth=38&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=ud71e4f99-6086-48e6-81b4-d4aa1167575&title=)] 是我们期望得到的电压矢量,T是一个PWM周期。
由正弦定理可得:
KaTeX parse error: \tag works only in display equations
其中
∣
U
4
∣
=
∣
U
6
∣
=
2
3
U
d
c
|U_4|=|U_6|=\frac{2}{3}U_{dc}
∣U4∣=∣U6∣=32Udc
整理可得在扇区I内,
U
4
U_4
U4、
U
6
U_6
U6以及零矢量所占时间:
KaTeX parse error: \tag works only in display equations
其中
m
=
3
∣
U
r
e
f
∣
U
d
c
m=\frac{\sqrt{3}|U_{ref}|}{U_{dc}}
m=Udc3∣Uref∣为SVPWM调制系数比(调制比)。在电流环控制过程中
m
m
m设置得越大代表了期望力矩越大。
当然
m
m
m并不是越大越好,需要使得合成矢量在线性区域内调制,则m满足以下条件:
KaTeX parse error: \tag works only in display equations
SPWM调制比为1,这就是SVPWM相比与SPWM对于直线母线电压利用率更高的原因,差不多高出
15.47
%
15.47\%
15.47%的效率。
在式(4)中得到了扇区I中任意合成矢量
U
r
e
f
U_{ref}
Uref的作用时间
T
0
(
T
7
)
T_0(T_7)
T0(T7)、
T
4
T_4
T4和
T
6
T_6
T6,零矢量
T
0
(
T
7
)
T_0(T_7)
T0(T7)的选择最具灵活性,分配的顺序也具有一定的灵活性,理论上一个周期内切换的顺序可以是任意的,只要满足条件即可,但是需要最大限度地减少开关损耗。
基本矢量作用顺序的分配原则:每次开关状态转换时,只改变其中一相的开关状态,并且对零矢量的时间进行平均分配,使产生的PWM对称,从而有效地降低PWM的谐波分量。
以下是各个扇区的
U
r
e
f
U_{ref}
Uref开关顺序如下表:
4.2 算法实现
4.2.1 参考电压矢量的扇区判断
用
U
α
U_\alpha
Uα和
U
β
U_\beta
Uβ表示参考电压矢量
U
r
e
f
U_{ref}
Uref在
α
\alpha
α、
β
\beta
β轴上的分量,定义
U
r
e
f
1
U_{ref1}
Uref1、
U
r
e
f
2
U_{ref2}
Uref2和
U
r
e
f
3
U_{ref3}
Uref3三个变量,于是有:
KaTeX parse error: \tag works only in display equations
如果
U
r
e
f
1
>
0
U_{ref1}>0
Uref1>0,则变量A=1,否则A=0;
如果
U
r
e
f
2
>
0
U_{ref2}>0
Uref2>0,则变量B=1,否则B=0;
如果
U
r
e
f
3
>
0
U_{ref3}>0
Uref3>0,则变量C=1,否则C=0;
令
N
=
A
×
2
0
+
B
×
2
1
+
C
×
2
2
=
A
+
2
B
+
4
C
N=A\times2^0+B\times2^1+C\times2^2=A+2B+4C
N=A×20+B×21+C×22=A+2B+4C,则可以得到N与扇区的关系如下表所示:
N | 3 | 1 | 5 | 4 | 6 | 2 |
---|---|---|---|---|---|---|
扇区 | I | II | III | IV | V | VI |
4.2.2 非零矢量和零矢量作用时间计算
根据式(4)可在扇区I时:
{
T
6
=
m
T
s
s
i
n
θ
T
4
=
m
T
s
s
i
n
(
π
3
−
θ
)
⇒
{
T
6
=
3
T
s
U
d
c
U
r
e
f
s
i
n
θ
T
4
=
3
T
s
U
d
c
U
r
e
f
s
i
n
(
π
3
−
θ
)
⇒
\left \{ \begin{array}{c} T_6=mT_ssin\theta \\ T_4=mT_ssin(\frac{\pi}{3}-\theta) \end{array} \right. \Rightarrow \left \{ \begin{array}{c} T_6=\frac{\sqrt{3}T_s}{U_{dc}}U_{ref}sin\theta \\ T_4=\frac{\sqrt{3}T_s}{U_{dc}}U_{ref}sin(\frac{\pi}{3}-\theta) \end{array} \right. \Rightarrow
{T6=mTssinθT4=mTssin(3π−θ)⇒{T6=Udc3TsUrefsinθT4=Udc3TsUrefsin(3π−θ)⇒
{
T
6
=
3
T
s
U
d
c
U
r
e
f
s
i
n
θ
T
4
=
3
T
s
U
d
c
U
r
e
f
(
s
i
n
π
3
c
o
s
θ
−
c
o
s
π
3
s
i
n
θ
)
⇒
{
T
6
=
3
T
s
U
d
c
U
r
e
f
s
i
n
θ
T
4
=
3
T
s
U
d
c
(
3
2
U
r
e
f
c
o
s
θ
−
1
2
U
r
e
f
s
i
n
θ
)
U
α
=
U
r
e
f
c
o
s
θ
,
U
β
=
U
r
e
f
s
i
n
θ
⇒
\left \{ \begin{array}{c} T_6=\frac{\sqrt{3}T_s}{U_{dc}}U_{ref}sin\theta \\ T_4=\frac{\sqrt{3}T_s}{U_{dc}}U_{ref}(sin\frac{\pi}{3}cos \theta- cos\frac{\pi}{3}sin \theta) \end{array} \right. \Rightarrow \left \{ \begin{array}{c} T_6=\frac{\sqrt{3}T_s}{U_{dc}}U_{ref}sin\theta \\ T_4=\frac{\sqrt{3}T_s}{U_{dc}}(\frac{\sqrt{3}}{2}U_{ref}cos \theta- \frac{1}{2}U_{ref}sin \theta) \\ U_\alpha=U_{ref}cos \theta, U_\beta=U_{ref}sin \theta\end{array} \right. \Rightarrow
{T6=Udc3TsUrefsinθT4=Udc3TsUref(sin3πcosθ−cos3πsinθ)⇒⎩
⎨
⎧T6=Udc3TsUrefsinθT4=Udc3Ts(23Urefcosθ−21Urefsinθ)Uα=Urefcosθ,Uβ=Urefsinθ⇒
KaTeX parse error: \tag works only in display equations
同理可得在扇区II时:
KaTeX parse error: \tag works only in display equations
同理可得在扇区III时:
KaTeX parse error: \tag works only in display equations
同理可得在扇区IV时:
KaTeX parse error: \tag works only in display equations
同理可得在扇区V时:
KaTeX parse error: \tag works only in display equations
同理可得在扇区VI时:
KaTeX parse error: \tag works only in display equations
由上面计算的结果,可以总结出以下表格:
4.2.3 过调制处理
在SVPWM的扇区I中,非零矢量
T
4
T_4
T4、
T
6
T_6
T6和零矢量的作用时间总和应为
T
s
T_s
Ts,以保持一个电机周期的完整性。然而,有时候
T
4
+
T
6
>
T
s
T_4+T_6>T_s
T4+T6>Ts,这可能会导致电机控制出现问题,例如电流畸变或转速不稳定。
为了解决这个问题,需要进行过调制处理,将
T
4
T_4
T4和
T
6
T_6
T6进行缩小,以保持电机周期的完整性,并确保控制信号的正确性,也可以保持SVPWM算法的准确性和稳定性,避免电机控制出现问题。
在扇区I中,如果
T
4
+
T
6
>
T
s
T_4+T_6>T_s
T4+T6>Ts则过调制处理过程为:
KaTeX parse error: \tag works only in display equations
其他扇区类似处理即可。
4.2.4 扇区矢量切换点的确定
在扇区I中七段式SVPWM的顺序是0-4-6-7-7-6-4-0,对称结构,由式(7)可得到非零矢量作用时间
T
4
T_4
T4、
T
6
T_6
T6和零矢量作用时间
T
0
T_0
T0和
T
7
T_7
T7。
且由上图可以得到扇区I三相桥臂的切换时间
SA桥臂切换时间:
T
a
=
1
2
T
0
=
1
4
(
T
s
−
T
4
−
T
6
)
T_a=\frac{1}{2}T_0=\frac{1}{4}(T_s-T_4-T_6)
Ta=21T0=41(Ts−T4−T6)
SB桥臂切换时间:
T
b
=
1
2
T
0
+
1
2
T
4
=
1
4
(
T
s
+
T
4
−
T
6
)
T_b=\frac{1}{2}T_0+\frac{1}{2}T_4=\frac{1}{4}(T_s+T_4-T_6)
Tb=21T0+21T4=41(Ts+T4−T6)
SC桥臂切换时间:
T
c
=
1
2
T
0
+
1
2
T
4
+
1
2
T
6
=
1
4
(
T
s
+
T
4
+
T
6
)
T_c=\frac{1}{2}T_0+\frac{1}{2}T_4+\frac{1}{2}T_6=\frac{1}{4}(T_s+T_4+T_6)
Tc=21T0+21T4+21T6=41(Ts+T4+T6)
同理可得扇区II三相桥臂的切换时间
SA桥臂切换时间:
T
a
=
1
2
T
0
+
1
2
T
2
=
1
4
(
T
s
+
T
2
−
T
6
)
T_a=\frac{1}{2}T_0+\frac{1}{2}T_2=\frac{1}{4}(T_s+T_2-T_6)
Ta=21T0+21T2=41(Ts+T2−T6)
SB桥臂切换时间:
T
b
=
1
2
T
0
=
1
4
(
T
s
−
T
2
−
T
6
)
T_b=\frac{1}{2}T_0=\frac{1}{4}(T_s-T_2-T_6)
Tb=21T0=41(Ts−T2−T6)
SC桥臂切换时间:
T
c
=
1
2
T
0
+
1
2
T
2
+
1
2
T
6
=
1
4
(
T
s
+
T
2
+
T
6
)
T_c=\frac{1}{2}T_0+\frac{1}{2}T_2+\frac{1}{2}T_6=\frac{1}{4}(T_s+T_2+T_6)
Tc=21T0+21T2+21T6=41(Ts+T2+T6)
同理可得扇区III三相桥臂的切换时间
SA桥臂切换时间:
T
a
=
1
2
T
0
+
1
2
T
2
+
1
2
T
3
=
1
4
(
T
s
+
T
2
+
T
3
)
T_a=\frac{1}{2}T_0+\frac{1}{2}T_2+\frac{1}{2}T_3=\frac{1}{4}(T_s+T_2+T_3)
Ta=21T0+21T2+21T3=41(Ts+T2+T3)
SB桥臂切换时间:
T
b
=
1
2
T
0
=
1
4
(
T
s
−
T
2
−
T
3
)
T_b=\frac{1}{2}T_0=\frac{1}{4}(T_s-T_2-T_3)
Tb=21T0=41(Ts−T2−T3)
SC桥臂切换时间:
T
c
=
1
2
T
0
+
1
2
T
2
=
1
4
(
T
s
+
T
2
−
T
3
)
T_c=\frac{1}{2}T_0+\frac{1}{2}T_2=\frac{1}{4}(T_s+T_2-T_3)
Tc=21T0+21T2=41(Ts+T2−T3)
同理可得扇区IV三相桥臂的切换时间
SA桥臂切换时间:
T
a
=
1
2
T
0
+
1
2
T
1
+
1
2
T
3
=
1
4
(
T
s
+
T
1
+
T
3
)
T_a=\frac{1}{2}T_0+\frac{1}{2}T_1+\frac{1}{2}T_3=\frac{1}{4}(T_s+T_1+T_3)
Ta=21T0+21T1+21T3=41(Ts+T1+T3)
SB桥臂切换时间:
T
b
=
1
2
T
0
+
1
2
T
1
=
1
4
(
T
s
+
T
1
−
T
3
)
T_b=\frac{1}{2}T_0+\frac{1}{2}T_1=\frac{1}{4}(T_s+T_1-T_3)
Tb=21T0+21T1=41(Ts+T1−T3)
SC桥臂切换时间:
T
c
=
1
2
T
0
=
1
4
(
T
s
−
T
1
−
T
3
)
T_c=\frac{1}{2}T_0=\frac{1}{4}(T_s-T_1-T_3)
Tc=21T0=41(Ts−T1−T3)
同理可得扇区V三相桥臂的切换时间
SA桥臂切换时间:
T
a
=
1
2
T
0
+
1
2
T
1
=
1
4
(
T
s
+
T
1
−
T
5
)
T_a=\frac{1}{2}T_0+\frac{1}{2}T_1=\frac{1}{4}(T_s+T_1-T_5)
Ta=21T0+21T1=41(Ts+T1−T5)
SB桥臂切换时间:
T
b
=
1
2
T
0
+
1
2
T
1
+
1
2
T
5
=
1
4
(
T
s
+
T
1
+
T
5
)
T_b=\frac{1}{2}T_0+\frac{1}{2}T_1+\frac{1}{2}T_5=\frac{1}{4}(T_s+T_1+T_5)
Tb=21T0+21T1+21T5=41(Ts+T1+T5)
SC桥臂切换时间:
T
c
=
1
2
T
0
=
1
4
(
T
s
−
T
1
−
T
5
)
T_c=\frac{1}{2}T_0=\frac{1}{4}(T_s-T_1-T_5)
Tc=21T0=41(Ts−T1−T5)
同理可得扇区VI三相桥臂的切换时间
SA桥臂切换时间:
T
a
=
1
2
T
0
=
1
4
(
T
s
−
T
4
−
T
5
)
T_a=\frac{1}{2}T_0=\frac{1}{4}(T_s-T_4-T_5)
Ta=21T0=41(Ts−T4−T5)
SB桥臂切换时间:
T
b
=
1
2
T
0
+
1
2
T
1
+
1
2
T
5
=
1
4
(
T
s
+
T
4
+
T
5
)
T_b=\frac{1}{2}T_0+\frac{1}{2}T_1+\frac{1}{2}T_5=\frac{1}{4}(T_s+T_4+T_5)
Tb=21T0+21T1+21T5=41(Ts+T4+T5)
SC桥臂切换时间:
T
c
=
1
2
T
0
+
1
2
T
4
=
1
4
(
T
s
+
T
4
−
T
5
)
T_c=\frac{1}{2}T_0+\frac{1}{2}T_4=\frac{1}{4}(T_s+T_4-T_5)
Tc=21T0+21T4=41(Ts+T4−T5)
汇总可得各个扇区的切换时刻表如下所示:
除了用切换时刻还可以使用开关切换的总时间即占空比来处理,两种方法在本质上差不多。
得到扇区I三相桥臂的占空比
SA桥臂占空比:
T
a
=
(
T
4
+
T
6
+
T
7
)
/
T
s
T_a=(T_4+T_6+T_7)/T_s
Ta=(T4+T6+T7)/Ts
SB桥臂占空比:
T
b
=
(
T
6
+
T
7
)
/
T
s
T_b=(T_6+T_7)/Ts
Tb=(T6+T7)/Ts
SC桥臂占空比:
T
c
=
T
7
/
T
s
T_c=T_7/T_s
Tc=T7/Ts
同理可得扇区II三相桥臂的占空比
SA桥臂占空比:
T
a
=
(
T
6
+
T
7
)
/
T
s
T_a=(T_6+T_7)/T_s
Ta=(T6+T7)/Ts
SB桥臂占空比:
T
b
=
(
T
2
+
T
6
+
T
7
)
/
T
s
T_b=(T_2+T_6+T_7)/Ts
Tb=(T2+T6+T7)/Ts
SC桥臂占空比:
T
c
=
T
7
/
T
s
T_c=T_7/T_s
Tc=T7/Ts
同理可得扇区III三相桥臂的占空比
SA桥臂占空比:
T
a
=
T
7
/
T
s
T_a=T_7/T_s
Ta=T7/Ts
SB桥臂占空比:
T
b
=
(
T
2
+
T
3
+
T
7
)
/
T
s
T_b=(T_2+T_3+T_7)/Ts
Tb=(T2+T3+T7)/Ts
SC桥臂占空比:
T
c
=
(
T
3
+
T
7
)
/
T
s
T_c=(T_3+T_7)/T_s
Tc=(T3+T7)/Ts
同理可得扇区IV三相桥臂的占空比
SA桥臂占空比:
T
a
=
T
7
/
T
s
T_a=T_7/T_s
Ta=T7/Ts
SB桥臂占空比:
T
b
=
(
T
3
+
T
7
)
/
T
s
T_b=(T_3+T_7)/Ts
Tb=(T3+T7)/Ts
SC桥臂占空比:
T
c
=
(
T
1
+
T
3
+
T
7
)
/
T
s
T_c=(T_1+T_3+T_7)/T_s
Tc=(T1+T3+T7)/Ts
同理可得扇区V三相桥臂的占空比
SA桥臂占空比:
T
a
=
(
T
5
+
T
7
)
/
T
s
T_a=(T_5+T_7)/T_s
Ta=(T5+T7)/Ts
SB桥臂占空比:
T
b
=
T
7
/
T
s
T_b=T_7/Ts
Tb=T7/Ts
SC桥臂占空比:
T
c
=
(
T
1
+
T
5
+
T
7
)
/
T
s
T_c=(T_1+T_5+T_7)/T_s
Tc=(T1+T5+T7)/Ts
同理可得扇区VI三相桥臂的占空比
SA桥臂占空比:
T
a
=
(
T
4
+
T
5
+
T
7
)
/
T
s
T_a=(T_4+T_5+T_7)/T_s
Ta=(T4+T5+T7)/Ts
SB桥臂占空比:
T
b
=
T
7
/
T
s
T_b=T_7/Ts
Tb=T7/Ts
SC桥臂占空比:
T
c
=
(
T
5
+
T
7
)
/
T
s
T_c=(T_5+T_7)/T_s
Tc=(T5+T7)/Ts
4.2.5 程序实现
首先实现基础的FOC算法:
#include <iostream>
#include "foc.h"
#include <fstream>
#include <cstdint>
int main()
{
foc_val_t foc_val;
std::ofstream fout("test_foc.csv");
std::cout << "This is Foc test!";
for (double theta = 0; theta < 10; theta+=0.01)//开环
{
foc_val.Udq.q = 0;
foc_val.Udq.d = 0.01;
alphaBeta_t alphaBeta= Rev_Park(foc_val.Udq, theta);
tabc_t tabc=svpwm(alphaBeta, theta);
double u_a = tabc.ta - 0.5 * (tabc.tb + tabc.tc);
double u_b = tabc.tb - 0.5 * (tabc.ta + tabc.tc);
double u_c = - (tabc.ta + tabc.tb);
fout << tabc.ta << ',' << tabc.tb << ',' << tabc.tc << '\n';
std::cout << tabc.ta << ',' << tabc.tb << ',' << tabc.tc << '\n';
}
}
#pragma once
#include <iostream>
typedef struct
{
int16_t hCos;
int16_t hSin;
} Trig_Components;
/* Macros ---------------------------------------------------------------- */
typedef struct
{
float ia;
float ib;
float ic;
}abc_t;
typedef struct
{
float ta;
float tb;
float tc;
}tabc_t;
typedef struct
{
float d;
float d_filter;
float q;
float q_filter;
}dq_t;
typedef struct
{
float alpha;
float beta;
}alphaBeta_t;
typedef struct
{
abc_t Iab;
alphaBeta_t I_alphaBeta;
dq_t Idq_ref;
dq_t Idq;
tabc_t tabc;
alphaBeta_t U_alphaBeta;
dq_t Udq;
}foc_val_t;
extern foc_val_t foc_val;
Trig_Components Trig_Functions(int16_t hAngle);
alphaBeta_t Clark(abc_t input);
dq_t Park(alphaBeta_t input, int16_t theta);
//alphaBeta_t Rev_Park(dq_t input, int16_t theta);
//tabc_t svpwm(alphaBeta_t input, int16_t theta);
alphaBeta_t Rev_Park(dq_t input, float theta);
tabc_t svpwm(alphaBeta_t input, float theta);
#include "foc.h"
#include "cmath"
/**********************************************function************************************************************************/
alphaBeta_t Rev_Park(dq_t input, float theta)
{
alphaBeta_t output;
Trig_Components TempSinCos;
float cos_da, sin_da;
float I_alpha_ratio, I_beta_ratio;
//TempSinCos = Trig_Functions(theta); //get sin_cos value
//cos_da = (float)(TempSinCos.hCos * DIV_Q15); //sin_cos is 0-32768 or -32768-0,sin_cos/32768 is 0-1
//sin_da = (float)(TempSinCos.hSin * DIV_Q15); //sin_cos is 0-32768 or -32768-0,sin_cos/32768 is 0-1
//output.alpha = input.d * cos_da - input.q * sin_da;
//output.beta = input.d * sin_da + input.q * cos_da;
output.alpha = input.d * cos(theta) - input.q * sin(theta);
output.beta = input.d * sin(theta) + input.q * cos(theta);
return (output);
}
tabc_t svpwm(alphaBeta_t input, float theta)
{
float u1 = 0, u2 = 0, u3 = 0;
float ts = 1;
float k = 1.732 * ts / 1; //Ts=1,Uds=1
tabc_t output;
float t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t0 = 0, t7 = 0;
u1 = input.beta;
u2 = input.alpha * 0.866 - 0.5 * input.beta; //sqrt(3)*U_alpha/2-U_beta/2
u3 = - input.alpha * 0.866 - 0.5 * input.beta; //-sqrt(3)*U_alpha/2-U_beta/2
uint8_t index = (u1 > 0) + (u2 > 0 ) * 2 + (u3 > 0 ) * 4;
switch (index)
{
case 3://sector 1
t4 = k * u2;
t6 = k * u1;
if (fabs(t4 + t6) > ts)
{
t4 = t4 * ts / (t4 + t6);
t6 = t6 * ts / (t4 + t6);
}
t7 = 0.5 * (ts - t4 - t6);
output.ta = t4 + t6 + t7;
output.tb = t6 + t7;
output.tc = t7;
break;
case 1://sector 2
t2 = - k * u2;
t6 = - k * u3;
if (fabs(t2 + t6) > ts)
{
t2 = t2 * ts / (t2 + t6);
t6 = t6 * ts / (t2 + t6);
}
t7 = 0.5 * (ts - t2 - t6);
output.ta = t6 + t7;
output.tb = t2 + t6 + t7;
output.tc = t7;
break;
case 5://sector 3
t2 = k * u1;
t3 = k * u3;
if (fabs(t2 + t3) > ts)
{
t2 = t2 * ts / (t2 + t3);
t3 = t3 * ts / (t2 + t3);
}
t7 = 0.5 * (ts - t2 - t3);
output.ta = t7;
output.tb = t2 + t3 + t7;
output.tc = t3 + t7;
break;
case 4://sector 4
t3 = - k * u2;
t1 = - k * u1;
if (fabs(t1 + t3) > ts)
{
t3 = t3 * ts / (t1 + t3);
t1 = t1 * ts / (t1 + t3);
}
t7 = 0.5 * (ts - t1 - t3);
output.ta = t7;
output.tb = t3 + t7;
output.tc = t1 + t3 + t7;
break;
case 6://sector 5
t1 = k * u3;
t5 = k * u2;
if (fabs(t1 + t5) > ts)
{
t1 = t1 * ts / (t1 + t5);
t5 = t5 * ts / (t1 + t5);
}
t7 = 0.5 * (ts - t1 - t5);
output.ta = t5 + t7;
output.tb = t7;
output.tc = t1 + t5 + t7;
break;
case 2://sector 6
t4 = - k * u3;
t5 = - k * u1;
if (fabs(t4 + t5) > ts)
{
t4 = t4 * ts / (t4 + t5);
t5 = t5 * ts / (t4 + t5);
}
t7 = 0.5 * (ts - t4 - t5);
output.ta = t4 + t5 + t7;
output.tb = t7;
output.tc = t5 + t7;
break;
default:
output.ta = 0.5;
output.tb = 0.5;
output.tc = 0.5;
break;
}
return output;
}
分析数据验证:
由结果可以得到svpwm产生了三相相位差120°的马鞍波电压,说明算法是正确的。
到这里只是说明svpwm算法是正确的,但在单片机里如何处理呢,单片机的计算能力和存储能力都不及强大的CPU,在单片机里处理算法有很多问题需要考虑,要考虑计算量,计算时间以及处理的方便性。
其实处理也简单,归一化处理,例如将正余弦0-1范围的小数,折算到0-32768的数值计算,避免了浮点数的计算。
5、PID控制
PID控制器(比例-积分-微分控制器),由比例单元(Proportional)、积分单元(Integral)和微分单元(Derivative)组成。可以透过调整这三个单元的增益来调定其特性。PID控制器主要适用于基本上线性,且动态特性不随时间变化的系统。
{
U
(
x
)
=
k
p
(
e
r
r
(
t
)
+
1
T
I
∫
e
r
r
(
t
)
d
t
+
T
D
d
e
r
r
(
t
)
d
t
)
=
K
p
e
r
r
(
t
)
+
K
i
∫
e
r
r
(
t
)
d
t
+
K
d
d
e
r
r
(
t
)
d
t
e
r
r
(
t
)
=
r
i
n
t
(
t
)
−
r
o
u
t
(
t
)
\left \{ \begin{array}{c} U(x)=k_p(err(t)+\frac{1}{T_I}\int err(t)dt+\frac{T_Dderr(t)}{dt})=K_perr(t)+K_i\int err(t)dt+K_d\frac{derr(t)}{dt} \\ err(t)=rint(t)-rout(t) \end{array} \right.
{U(x)=kp(err(t)+TI1∫err(t)dt+dtTDderr(t))=Kperr(t)+Ki∫err(t)dt+Kddtderr(t)err(t)=rint(t)−rout(t)
从信号变换的角度而言,超前校正、滞后校正、滞后-超前校正可以总结为比例、积分、微分三种运算及其组合。
-
比例控制可快速、及时、按比例调节偏差,提高控制灵敏度,但有静差,控制精度低。
-
积分控制能消除偏差,提高控制精度、改善稳态性能,但易引起震荡,造成超调。
-
微分控制是一种超前控制,能调节系统速度、减小超调量、提高稳定性,但其时间常数过大会引入干扰、系统冲击大,过小则调节周期长、效果不显著。
比例、积分、微分控制相互配合,合理选择PID调节器的参数,即比例系数KP、积分时间常数τi和微分时间常数τD,可迅速、准确、平稳的消除偏差,达到良好的控制效果。
上面的公式是连续的,在计算机及单片机中处理时需要离散化处理。
5.1 离散化处理
假设采样间隔为
T
T
T,则在第
k
k
k个
T
T
T时刻:
偏差
e
r
r
(
k
)
=
r
i
n
(
k
)
−
r
o
u
t
(
k
)
err(k)=rin(k)-rout(k)
err(k)=rin(k)−rout(k);
积分环节用加和的形式表示,即
e
r
r
(
k
)
+
e
r
r
(
k
+
1
)
+
…
…
err(k)+err(k+1)+……
err(k)+err(k+1)+……;
微分环节用斜率的形式表示,即
[
e
r
r
(
k
)
−
e
r
r
(
k
−
1
)
]
/
T
[err(k)-err(k-1)]/T
[err(k)−err(k−1)]/T;
从而形成如下PID离散表示形式:
KaTeX parse error: {equation} can be used only in display mode.
PID有位置式和增量式两种,上式就是位置式,增量式计算如下,在第
k
−
1
k-1
k−1个
T
T
T时刻:
KaTeX parse error: \tag works only in display equations
式(1)减去式(2)
U
(
k
)
−
U
(
k
−
1
)
U(k)-U(k-1)
U(k)−U(k−1)且有:
KaTeX parse error: \tag works only in display equations
那么增量式PID就有:
KaTeX parse error: \tag works only in display equations
5.2 位置式PID和增量式PID控制算法的区别
位置式 PID 和增量式 PID 控制算法的区别:
(1)位置式PID控制的输出与整个过去的状态有关,用到了误差的累加值;而增量式PID的输出只与当前拍和前两拍的误差有关,因此位置式PID控制的累积误差相对更大;
(2)增量式PID控制输出的是控制量增量,并无积分作用,因此该方法适用于执行机构带积分部件的对象,如步进电机等,而位置式PID适用于执行机构不带积分部件的对象,如电液伺服阀。
(3)由于增量式PID输出的是控制量增量,如果计算机出现故障,误动作影响较小,而执行机构本身有记忆功能,可仍保持原位,不会严重影响系统的工作,而位置式的输出直接对应对象的输出,因此对系统影响较大。
5.3 程序实现
在这里我们不使用微分,主要是因为微分如果参数调的不好的话,在有噪声的系统中会放大噪声,因此在这里只使用比例和积分调节。
以位置式PID为例:
#pragma once
#include <iostream>
typedef struct
{
float rin;
float rout;
float err;
float kp;
float ki;
float kd;
float interal;
}pid_t;
extern pid_t pid;
float PID_Calc(pid_t input, float err);
#include "pid.h"
#include "cmath"
float PID_Calc(pid_t input,float err)
{
float Proportional_temp = 0, Integral_temp = 0, Integral_sum_temp = 0;
Proportional_temp = input.kp * err;
Integral_temp = input.ki * err;
Integral_sum_temp = input.interal+ Integral_temp;
input.rout = Integral_sum_temp + Proportional_temp;
return input.rout;
}
5.4 参数整定
工程整定方法(工程经验调参):
PID控制器参数的工程整定方法,主要有临界比例法、反应曲线法和衰减法。三种方法各有其特点,其共同点都是通过试验,然后按照工程经验公式对控制器参数进行整定。但无论采用哪一种方法所得到的控制器参数,都需要在实际运行中进行最后调整与完善。现在一般采用的是临界比例法。
PID调试一般原则
- 在输出不振荡时,增大比例增益P
- 在输出不振荡时,减小积分时间常数Ti
- 在输出不振荡时,增大微分时间常数Td
1)确定比例增益P
确定比例增益P 时,首先去掉PID的积分项和微分项,一般是令Ti=0、Td=0(具体见PID的参数设定说明),使PID为纯比例调节。输入设定为系统允许的最大值的60%70%,由0逐渐加大比例增益P,直至系统出现振荡;再反过来,从此时的比例增益P逐渐减小,直至系统振荡消失,记录此时的比例增益P,设定PID的比例增益P为当前值的**60%70%**。比例增益P调试完成。
2)确定积分时间常数Ti
比例增益P确定后,设定一个较大的积分时间常数Ti的初值,然后逐渐减小Ti,直至系统出现振荡,之后在反过来,逐渐加大Ti,直至系统振荡消失。记录此时的Ti,设定PID的积分时间常数Ti为当前值的150%~180%。积分时间常数Ti调试完成。
3)确定微分时间常数Td
微分时间常数Td一般不用设定,为0即可。若要设定,与确定P和Ti的方法相同,取不振荡时的30%。
4)系统空载、带载联调,再对PID参数进行微调,直至满足要求。
变速积分的基本思想是,设法改变积分项的累加速度,使其与偏差大小相对应:偏差越大,积分越慢;反之则越快,有利于提高系统品质。
5.5 参数自整定算法
预留
6、磁链圆限制
磁链圆限制(flux circle limitation)是一种保护电机和控制系统的技术。它的目的是限制电机的磁链(flux)在一定的范围内,避免电机工作在过饱和或过磁饱和状态下。
磁链圆限制是为了防止以下情况发生:
- 磁链过饱和(Magnetic Flux Saturation):当电机磁链超过一定的限制值时,磁链的增长速率会变得非常缓慢,这会导致电机性能下降,并可能产生不可预测的响应。过饱和可能会引起电机振动、噪声和损坏,还可能导致电机控制系统的不稳定。
- 磁链过磁饱和(Magnetic Flux Demagnetization):过磁饱和是指磁链降低到不可接受的水平,导致电机无法提供预期的输出扭矩。过磁饱和可能会导致电机失去控制、失去动力或停机。
通过限制磁链在合适的范围内,磁链圆限制可以确保电机在正常工作范围内运行,提供稳定的性能和可靠性。它通常通过对电机控制系统中的电流、电压或磁场进行限制来实现。
6.1 确定MAX_MODULE值
假设磁链圆的最大矢量值为1,但因FOC控制中需要设定PWM死区时间,以及PWM载波频率对AD采样时间的影响,使PWM占空比值最大不能达到100%,需要留出时间给ADC采样电机电流,所以矢量的最大值不能达到1。
因FOC中使用Q15格式处理小数,所以设定矢量为1时(PWM最大占空比100%) MAX_MODULE = 32767;若PWM占空比最大为97%,则MAX_MODULE = 0.97 × 32767;
6.2 磁链限制原理
磁链限制函数在FOC流程框架图中,在PID控制器之后,而PID控制器是单独对
V
d
V_d
Vd,
V
q
V_q
Vq进行PID控制的,所以为了使
V
d
V_d
Vd,
V
q
V_q
Vq合成的电压矢量小于等于单位圆的边,即
V
d
²
+
V
q
²
≤
M
A
X
_
M
O
D
U
L
E
²
V_d^² + V_q^² ≤ MAX\_MODULE^²
Vd²+Vq²≤MAX_MODULE²。
其原理公式如下,若
V
d
V_d
Vd,
V
q
V_q
Vq合成的矢量大于圆的最大矢量,则将其乘以一个缩放倍数
i
2
i²
i2,使其等于圆的最大矢量,
i
i
i就是需要缩放的系数。
令
(
V
d
²
+
V
q
²
)
×
i
²
=
M
A
X
_
M
O
D
U
L
E
²
⇒
i
=
M
A
X
_
M
O
D
U
L
E
²
/
(
V
d
²
+
V
q
²
)
(V_d^² + V_q^² ) × i^² = MAX\_MODULE^² \Rightarrow i = \sqrt{ MAX\_MODULE^² / (V_d^² + V_q^²) }
(Vd²+Vq²)×i²=MAX_MODULE²⇒i=MAX_MODULE²/(Vd²+Vq²)
STM32在计算开根号上比较费时,所以ST电机库中引入查表去查开根号值。
6.3 确定 START_INDEX值
因
V
d
V_d
Vd与
V
q
V_q
Vq都是int_16类型,其最大值为S16_MAX (32767)
所以需要限制的范围满足
V
d
²
+
V
q
²
≤
M
A
X
_
M
O
D
U
L
E
²
V_d^² + V_q^² ≤ MAX\_MODULE^²
Vd²+Vq²≤MAX_MODULE² 也就是
(
M
A
X
_
M
O
D
U
L
E
²
+
1
)
~
(
2
×
S
16
_
M
A
X
²
)
( MAX\_MODULE^² + 1 )~ ( 2 × S16\_MAX^² )
(MAX_MODULE²+1)~(2×S16_MAX²)
即需要制表的值
i
=
M
A
X
_
M
O
D
U
L
E
²
/
(
M
A
X
_
M
O
D
U
L
E
²
+
1
)
~
M
A
X
_
M
O
D
U
L
E
²
/
(
2
×
S
16
_
M
A
X
²
)
i = \sqrt{ MAX\_MODULE^² / ( MAX\_MODULE^² + 1) ~ MAX\_MODULE^² / ( 2 × S16\_MAX^² ) }
i=MAX_MODULE²/(MAX_MODULE²+1)~MAX_MODULE²/(2×S16_MAX²);
而
i
⊆
(
0
,
1
)
i \subseteq(0,1)
i⊆(0,1) 这段内容则不需要进行制表,所以需要定制一个制表的开头位置。
START_INDEX 是为了求出在全段范围内,不需要进行限制的个数。
设定
M
A
X
_
M
O
D
U
L
E
²
/
(
M
A
X
_
M
O
D
U
L
E
²
+
1
)
~
M
A
X
_
M
O
D
U
L
E
²
/
(
2
×
S
16
_
M
A
X
²
)
MAX\_MODULE^² / ( MAX\_MODULE^² + 1) ~ MAX\_MODULE^² / ( 2 × S16\_MAX^² )
MAX_MODULE²/(MAX_MODULE²+1)~MAX_MODULE²/(2×S16_MAX²)需要制定count个值,则不需要限制范围个数
S
T
A
R
T
_
I
N
D
E
X
=
(
M
A
X
_
M
O
D
U
L
E
2
)
/
(
2
×
S
16
_
M
A
X
²
)
×
c
o
u
n
t
START\_INDEX = (MAX\_MODULE²) / (2 \times S16\_MAX^²) \times count
START_INDEX=(MAX_MODULE2)/(2×S16_MAX²)×count
则制表需要数据个数
n
=
c
o
u
n
t
−
S
T
A
R
T
_
I
N
D
E
X
n = count - START\_INDEX
n=count−START_INDEX
将制表的范围用MIN,MAX表示:
{
M
I
N
=
M
A
X
_
M
O
D
U
L
E
2
/
(
M
A
X
_
M
O
D
U
L
E
2
+
1
)
×
Q
15
M
A
X
=
M
A
X
_
M
O
D
U
L
E
2
/
(
2
×
S
1
6
M
A
X
2
)
×
Q
15
\left \{ \begin{array}{c} MIN = \sqrt{ MAX\_MODULE² / ( MAX\_MODULE² + 1 ) } × Q15 \\ MAX = \sqrt{ MAX\_MODULE² / ( 2 × S16_MAX ² ) } × Q15 \end{array} \right.
{MIN=MAX_MODULE2/(MAX_MODULE2+1)×Q15MAX=MAX_MODULE2/(2×S16MAX2)×Q15
则制表数组每个数值
i
=
M
I
N
+
(
M
A
X
−
M
I
N
)
/
n
×
x
i = MIN + (MAX - MIN)/n × x
i=MIN+(MAX−MIN)/n×x
设定count = 128, 当PWM占空比最大为100%时, MAX_MODULE = 32767,START_INDEX = 64,n = 128 - 64 = 64.
6.4 程序实现
uint16_t Circle_limit_table[65] = { 32768, 32515 ,32268 ,32026 ,31790 ,31558 ,31332 ,31111 ,30894 ,30682 ,
30474 ,30270 ,30070 ,29874 ,29682 ,29494 ,29309 ,29127 ,28949 ,28774 ,
28602 ,28434 ,28268 ,28105 ,27945 ,27787 ,27632 ,27480 ,27330 ,27183 ,
27038 ,26895 ,26755 ,26617 ,26481 ,26346 ,26214 ,26084 ,25956 ,25830 ,
25705 ,25583 ,25462 ,25342 ,25225 ,25109 ,24994 ,24882 ,24770 ,24660 ,
24552 ,24445 ,24339 ,24235 ,24132 ,24031 ,23930 ,23831 ,23733 ,23637 ,
23541 ,23447 ,23354 ,23262 ,23170 }; //i = sqrt(64/m)*Q15 Q15 = 32768
uint16_t MaxModule = 32767; /**< Circle limitation maximum allowed module */
uint8_t Start_index = 64; /**< Circle limitation table indexing start */
qd_t Circle_Limitation(qd_t Vqd)
{
uint16_t table_element;
uint32_t uw_temp;
int32_t sw_temp;
qd_t local_vqd = Vqd;
sw_temp = ( int32_t )( Vqd.q ) * Vqd.q + //temp = vq2 + vd2;
( int32_t )( Vqd.d ) * Vqd.d;
uw_temp = ( uint32_t ) sw_temp;
/* uw_temp min value 0, max value 32767*32767 */
if ( uw_temp > ( MaxModule * MaxModule ))
{
uw_temp = (uw_temp - 64) / (MaxModule * MaxModule / 64) + 1;
/* wtemp min value pHandle->Start_index, max value 127 */
uw_temp -= Start_index;
/* uw_temp min value 0, max value 127 - pHandle->Start_index */
table_element = Circle_limit_table[uw_temp];
sw_temp = Vqd.q * (int32_t)table_element;
local_vqd.q = (int16_t)(sw_temp / 32768);
sw_temp = Vqd.d * (int32_t)( table_element );
local_vqd.d = (int16_t)(sw_temp / 32768);
}
return ( local_vqd );
}
参考:
有感FOC算法学习与实现总结:https://www.cnblogs.com/unclemac/p/12783366.html?share_token=2D91E9DE-C18B-43B8-B2AD-304FFE17B3AB&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_ios&utm_campaign=client_share&wxshare_count=1
FOC中的Clarke变换和Park变换详解(动图+推导+仿真+附件代码):
https://www.cnblogs.com/unclemac/p/12783309.html
内置式永磁同步电机PMSM的矢量控制:
https://blog.csdn.net/jaysur/article/details/103865717
FOC中的SVPWM原理细讲:
https://zhuanlan.zhihu.com/p/466883185
FOC算法与SVPWM技术:
https://blog.csdn.net/qq_41990294/article/details/128405398?share_token=7AC0CFF2-CC2D-4571-B0B3-1AD1622B77F8&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_ios&utm_campaign=client_share&wxshare_count=1
【SVPWM原理与搭建思路-哔哩哔哩】 https://b23.tv/YPa07W5
简述FOC电机控制之SVPWM原理(下)
https://m.elecfans.com/article/2063607.html?share_token=980CCA7A-35DD-49B8-8726-73204B6E65F4&tt_from=weixin&utm_source=weixin&utm_medium=toutiao_ios&utm_campaign=client_share&wxshare_count=1
FOC入门教程:
https://blog.csdn.net/qq_35947329/article/details/115483413