今天获知了,电机FOC包含了SVPWM、坐标转换、信号采集反馈、PID闭环控制等,这个控制策略,统称为FOC控制。一般SVPWM算法的实现是在静止的αβ坐标系上实现。而PID控制器由于是对直流参考信号的跟踪效果较好,因此三相交流电会经过坐标变换,在旋转的dq坐标轴上,可以用直流量描述电枢绕组的合成矢量。
FOC控制中,有两种坐标转换需要注意的,分别是clark变换,和park变换。clark变换将abc坐标系转换为αβ坐标系,而park变换将静止的αβ坐标系转换为旋转的dq坐标系。
1 clark变换
其实直接可以把转换公式列出。
写成转换矩阵,就是:
clark变换的逆变换:
写成转换矩阵,就是:
将两个转换矩阵相乘,应该是一个单位矩阵,系数K的作用是可以将转换变为等幅值转换或者等功率转换。
当,是等幅值转换;当
,是等功率转换。
1.1 matlab仿真
在matlab/simulink中搭建仿真模型:
abcToAlphabeta中的代码:
-
function y = fcn(a,b,
c)
-
%#eml
-
-
-
alpha = a - b/
2 -
c/
2;
-
beta = sqrt(
3)/
2 * (b -
c);
-
y = (
2/
3)*[alpha;beta];
alphabetaToABC中的代码:
-
function y = fcn(alpha,beta)
-
%#
eml
-
-
a =
alpha;
-
b = -
1/
2 * alpha + sqrt(
3)/
2 * beta;
-
c = -
1/
2 * alpha - sqrt(
3)/
2 * beta;
-
-
y = [a;b;c];
仿真波形:
我在这里使用的是等幅值变换。因为这里调制系数为1,各个正弦波的幅值都是1。假如使用等功率变换,alphabeta坐标系上的幅值会超过1,此时若直接经过SVPWM算法,会变成过调制。
2 park变换
通过几何变换,可以直接得到
图中就是d轴和α轴之间的夹角。我们也可以用q轴和α轴之间的夹角进行转换,但是会影响矩阵的参数。故还是采用d轴和α轴之间的夹角。因为我参考了wikipedia的alphabeta transformation和TI的controlSuite里面的资料,都是使用这个夹角去推转换矩阵的。因此不转牛角尖了。
写成矩阵的形式:
那么逆变换就是:
2.1 仿真
搭建仿真模型:
alphabetaToDQ代码:
-
function y = fcn(alpha,beta, c)
-
%#eml
-
d =
cos(c)* alpha +
sin(c)*beta;
-
q = -
sin(c)* alpha +
cos(c)*beta;
-
-
y=[d;q];
DQToAlphabeta代码:
-
function y = fcn(d,q, c)
-
%#eml
-
alpha =
cos(c) * d -
sin(c)*q;
-
beta =
sin(c) * d +
cos(c)*q;
-
-
y=[alpha;beta];
波形:
此时注意到:
现在三相abc的波形函数是:
假如需要反转,那么把输入改为:
同时把仿真模型中的constant改为 -2*pi*10
可以得到:
3 C语言
以下代码来自TI的controlSUITE。在此特别鸣谢TI。
3.1 clarke.h
-
/* =================================================================================
-
File name: CLARKE.H
-
===================================================================================*/
-
-
-
#ifndef __CLARKE_H__
-
#define __CLARKE_H__
-
-
typedef
struct { _iq As;
// Input: phase-a stator variable
-
_iq Bs;
// Input: phase-b stator variable
-
_iq Cs;
// Input: phase-c stator variable
-
_iq Alpha;
// Output: stationary d-axis stator variable
-
_iq Beta;
// Output: stationary q-axis stator variable
-
} CLARKE;
-
-
/*-----------------------------------------------------------------------------
-
Default initalizer for the CLARKE object.
-
-----------------------------------------------------------------------------*/
-
#define CLARKE_DEFAULTS { 0, \
-
0, \
-
0, \
-
0, \
-
0, \
-
}
-
-
/*------------------------------------------------------------------------------
-
CLARKE Transformation Macro Definition
-
------------------------------------------------------------------------------*/
-
-
// 1/sqrt(3) = 0.57735026918963
-
#define ONEbySQRT3 0.57735026918963 /* 1/sqrt(3) */
-
-
-
// Clarke transform macro (with 2 currents)
-
//==========================================
-
#define CLARKE_MACRO(v) \
-
v.Alpha = v.As; \
-
v.Beta = _IQmpy((v.As +_IQmpy2(v.Bs)),_IQ(ONEbySQRT3));
-
-
-
// Clarke transform macro (with 3 currents)
-
//==========================================
-
#define CLARKE1_MACRO(v) \
-
v.Alpha = v.As; \
-
v.Beta = _IQmpy((v.Bs - v.Cs),_IQ(ONEbySQRT3));
-
-
#endif // __CLARKE_H__
-
3.2 park.h
-
/* =================================================================================
-
File name: PARK.H
-
===================================================================================*/
-
-
#ifndef __PARK_H__
-
#define __PARK_H__
-
-
typedef
struct { _iq Alpha;
// Input: stationary d-axis stator variable
-
_iq Beta;
// Input: stationary q-axis stator variable
-
_iq Angle;
// Input: rotating angle (pu)
-
_iq Ds;
// Output: rotating d-axis stator variable
-
_iq Qs;
// Output: rotating q-axis stator variable
-
_iq Sine;
-
_iq Cosine;
-
} PARK;
-
-
/*-----------------------------------------------------------------------------
-
Default initalizer for the PARK object.
-
-----------------------------------------------------------------------------*/
-
#define PARK_DEFAULTS { 0, \
-
0, \
-
0, \
-
0, \
-
0, \
-
0, \
-
0, \
-
}
-
-
/*------------------------------------------------------------------------------
-
PARK Transformation Macro Definition
-
------------------------------------------------------------------------------*/
-
-
-
#define PARK_MACRO(v) \
-
\
-
v.Ds = _IQmpy(v.Alpha,v.Cosine) + _IQmpy(v.Beta,v.Sine); \
-
v.Qs = _IQmpy(v.Beta,v.Cosine) - _IQmpy(v.Alpha,v.Sine);
-
-
#endif // __PARK_H__
3.3 ipark.h
-
/* =================================================================================
-
File name: IPARK.H
-
===================================================================================*/
-
-
#ifndef __IPARK_H__
-
#define __IPARK_H__
-
-
typedef
struct { _iq Alpha;
// Output: stationary d-axis stator variable
-
_iq Beta;
// Output: stationary q-axis stator variable
-
_iq Angle;
// Input: rotating angle (pu)
-
_iq Ds;
// Input: rotating d-axis stator variable
-
_iq Qs;
// Input: rotating q-axis stator variable
-
_iq Sine;
// Input: Sine term
-
_iq Cosine;
// Input: Cosine term
-
} IPARK;
-
-
/*-----------------------------------------------------------------------------
-
Default initalizer for the IPARK object.
-
-----------------------------------------------------------------------------*/
-
#define IPARK_DEFAULTS { 0, \
-
0, \
-
0, \
-
0, \
-
0, \
-
0, \
-
0, \
-
}
-
-
/*------------------------------------------------------------------------------
-
Inverse PARK Transformation Macro Definition
-
------------------------------------------------------------------------------*/
-
-
-
#define IPARK_MACRO(v) \
-
\
-
v.Alpha = _IQmpy(v.Ds,v.Cosine) - _IQmpy(v.Qs,v.Sine); \
-
v.Beta = _IQmpy(v.Qs,v.Cosine) + _IQmpy(v.Ds,v.Sine);
-
-
#endif // __IPARK_H__
-
小结
坐标变换在FOC中也是重要的部分。本文介绍了clark变换和park变换。这两种变换其实在网上资料十分丰富了。但在这里还是写了一遍。一方面是贡献自己的能力,另一方面是满足自己的收藏癖。假如需要重新编程,那么我还是会重新找出资料。但是目前TI的资料也很丰富,我往下在实物上实现FOC的话,估计会从现有的代码上修改。
现在干活都做LED了,看维基上面的clarke变换,让我想起了以前的日子。以前没搞懂的坐标公式和PID公式,多推几遍,现在也越来越熟悉了。