在上一篇文章中,我使用的是频率自适应的SOGI,并且最后采用了后向差分的方式实现SOGI,这样实现确实可以准确锁出频率和相角,
但除了频率和相角,通常我们还需要知道对象的幅值,***然而采用后向差分可能会导致计算出来的幅值出现小幅度的振荡***。
而采用双线性变换的离散化方式则没有这个问题,因此给出**双线性变换的实现过程**。
在上一篇文章中给出了SOGI连续域alpha和beta的输出表达式,这里将其分别进行后相差分和双线性变换离散,得到的表达式如下:
用MATLAB搭建仿真观察三个表达式的效果:
图一为传递函数的仿真模型,输入信号为频率50Hz幅值311的正弦信号。
图二展示了输入信号(红色)和三种形式传递函数的alpha输出,三种形式都能迅速跟上输入信号,只有很小的差别。
图三是根据三种形式传递函数的输出计算的幅值结果,即根号(alpha²+beta²),可以看到后向差分离散的结果(浅蓝色)存在抖动现象,因此在离散的时候可以选择双线性变换的方式。
双线性SOGI实现过程
/*首先定义一个结构体存放一些计算过程中用到的变量*/
struct SOGI
{
float w_p; //输出角频率
float v_p; //alpha输出(v')
float qv_p; //beta输出(qv')
float phase; //相角
float mag; //幅值
/// 改进直接程序法用到的中间变量
float qk0; //当前拍
float qk1; //上一拍
float qk2; //上上拍
///
float Ts; //采样周期
float err_v; //alpha误差
float *input; //输入信号
float sin;
}
struct SOGI FLL;
#deine FLL_QSGgain 1.414 //上一篇提到的参数k
#define FLL_NormalGgain -47 //上一篇提到的另一个叫不上名字的参数
#define PI 3.1415926535
void SOGI_clc() //计算函数
{
/// 根据上述双线性离散后的表达式得到的各项系数
den1 = 4 + FLL.w_p*FLL.w_p*FLL.Ts*FLL.Ts - 2*FLL_QSGgain*FLL.w_p*FLL.Ts;
den2 = 2*FLL.w_p*FLL.w_p*FLL.Ts*FLL.Ts - 8;
den3 = 4 + FLL.w_p*FLL.w_p*FLL.Ts*FLL.Ts + 2*FLL_QSGgain*FLL.w_p*FLL.Ts;
num1 = 2*FLL_QSGgain*FLL.w_p*FLL.Ts;
num2 = FLL_QSGgain*FLL.w_p*FLL.w_p*FLL.Ts*FLL.Ts;
///
FLL.qk0 = (*(FLL.input) - den2*FLL.qk1 - den1*FLL.qk2)/den3;
FLL.v_p = num1*(FLL.qk0 - FLL.qk2); //alpha
FLL.qv_p = num2*(FLL.qk0 + 2*FLL.qk1 + FLL.qk2); //beta
FLL.qk2 = FLL.qk1;
FLL.qk1 = FLL.qk0;
FLL.mag = sqrt(FLL.v_p*FLL.v_p + FLL.qv_p*FLL.qv_p);
FLL.phase = atan2(FLL.v_p,FLL.qv_p);
if(FLL.phase < 0)FLL.phase += 2*PI;
FLL.sin = sinf(FLL.phase);
//频率自适应
FLL.err_v = *(FLL.input) - FLL.v_p;
FLL.w_p += FLL.w_p*FLL.err_v*FLL.qv_p*FLL_QSGgain*FLL_NormalGgain / (FLL.v_p*FLL.v_p + FLL.qv_p*FLL.qv_p+0.1);
}