源码

SVM 函数的 alpha 和 beta 的值是经过了标幺化,基准值为 (最大相电压),也就是说 alpha 和 beta 的范围是 [-1,1]。约束:alpha-beta 向量的大小不得大于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Compute rising edge timings (0.0 - 1.0) as a function of alpha-beta
// as per the magnitude invariant clarke transform
// The magnitude of the alpha-beta vector may not be larger than sqrt(3)/2
// Returns true on success, and false if the input was out of range
std::tuple<float, float, float, bool> SVM(float alpha, float beta) {
float tA, tB, tC;
int Sextant;

if (beta >= 0.0f) {
if (alpha >= 0.0f) {
//quadrant I
if (one_by_sqrt3 * beta > alpha)
Sextant = 2; //sextant v2-v3
else
Sextant = 1; //sextant v1-v2
} else {
//quadrant II
if (-one_by_sqrt3 * beta > alpha)
Sextant = 3; //sextant v3-v4
else
Sextant = 2; //sextant v2-v3
}
} else {
if (alpha >= 0.0f) {
//quadrant IV
if (-one_by_sqrt3 * beta > alpha)
Sextant = 5; //sextant v5-v6
else
Sextant = 6; //sextant v6-v1
} else {
//quadrant III
if (one_by_sqrt3 * beta > alpha)
Sextant = 4; //sextant v4-v5
else
Sextant = 5; //sextant v5-v6
}
}

switch (Sextant) {
// sextant v1-v2
case 1: {
// Vector on-times
float t1 = alpha - one_by_sqrt3 * beta;
float t2 = two_by_sqrt3 * beta;

// PWM timings
tA = (1.0f - t1 - t2) * 0.5f;
tB = tA + t1;
tC = tB + t2;
} break;

// sextant v2-v3
case 2: {
// Vector on-times
float t2 = alpha + one_by_sqrt3 * beta;
float t3 = -alpha + one_by_sqrt3 * beta;

// PWM timings
tB = (1.0f - t2 - t3) * 0.5f;
tA = tB + t3;
tC = tA + t2;
} break;

// sextant v3-v4
case 3: {
// Vector on-times
float t3 = two_by_sqrt3 * beta;
float t4 = -alpha - one_by_sqrt3 * beta;

// PWM timings
tB = (1.0f - t3 - t4) * 0.5f;
tC = tB + t3;
tA = tC + t4;
} break;

// sextant v4-v5
case 4: {
// Vector on-times
float t4 = -alpha + one_by_sqrt3 * beta;
float t5 = -two_by_sqrt3 * beta;

// PWM timings
tC = (1.0f - t4 - t5) * 0.5f;
tB = tC + t5;
tA = tB + t4;
} break;

// sextant v5-v6
case 5: {
// Vector on-times
float t5 = -alpha - one_by_sqrt3 * beta;
float t6 = alpha - one_by_sqrt3 * beta;

// PWM timings
tC = (1.0f - t5 - t6) * 0.5f;
tA = tC + t5;
tB = tA + t6;
} break;

// sextant v6-v1
case 6: {
// Vector on-times
float t6 = -two_by_sqrt3 * beta;
float t1 = alpha + one_by_sqrt3 * beta;

// PWM timings
tA = (1.0f - t6 - t1) * 0.5f;
tC = tA + t1;
tB = tC + t6;
} break;
}

bool result_valid =
tA >= 0.0f && tA <= 1.0f
&& tB >= 0.0f && tB <= 1.0f
&& tC >= 0.0f && tC <= 1.0f;
return {tA, tB, tC, result_valid};
}

函数主体上可以分为 2 大块,第一大块是个复合的 if 语句,用于判断扇区,第二个则是个 switch 语句,用于计算定时器的比较值,用于产生不同占空比的 PWM。

扇区判断

对于第一部分扇区判断,以第 1 扇区为例说明。

如图 1 所示,给定的$ 使vref11 30°160° 110P100线PAΔOPAPAO=90°POA=60°OPA=30° 110$的值略大时,∠POA 都将小于 60°,合向量落入第 1 扇区。从数学上说

POA=arctanPAOA=arctanβα<60°

即可作为 1 扇区判断条件,坏消息是 arctan 在 MCU 上计算得慢,所以得换换思路。

tanPOA=βα

这是一个显而易见的结论,当合向量恰好位于 110 轴时tan60°= ,也就是= ,如果和程序中的表述一致的话,就是α=13β 。当β减小α不变或α增大β不变时,合向量都将从 110 轴转向 1 扇区,反之则转入 2 扇区。

综上所述得到结论,当>0,>0β>3α 合向量落在第 1 扇区; 当>0,>0β<3α,合向量落在第 2 扇区。

PWM 值计算

接下来聊一聊 PWM 比较值是如何计算的,这次以第 2 扇区为例,如图 2 所示。

在第 2 扇区的合向量是需要借助 010 和 110 这两个基本向量合成得到,传入 SVM 函数的参数 alpha 和 beta 的合向量是Vref。然后考虑将 αβ的值都分解到 010 和 110 这两个基本向量上。将α 在 100 轴的端点称为 A 点,β端点称为 B 点。

先试着分解α向量,过 A 点作 110(001)轴的平行线交 101 轴于 C 点。过 A 点作 010(101)轴平行线交 110 轴于 D 点。分析易得OACOAD 都是等边三角形。因此,α向量分解到 110 轴的长度也是α,分解到 010 轴的长度是α

然后分解β向量,过 B 点作 110 轴平行线交 010 轴于 E 点,过 B 点作 010 轴平行线交 110 轴于 F 点。易分析得 OBEOBF 为底角为 30°的等腰三角形,需求 OE 和 OF 长度,且 OE=OF=BF=BE。过 E 点作 OB 垂线交于 G,则 EGB为直角三角形,且EBG=30°BE=23BGBG=12βBE=13β 为所求。 可以给结论了,110 轴上产生作用力的时间定义为 t2,010 轴上产生作用力的时间定义为 t3。则有:

t3=α+13β

t2=α+13β

参考文献

https://zhuanlan.zhihu.com/p/506240030