最近在学习TI的TIDA-010062(DSP型号用的是TMS320F280049C),也就是1kW、80 Plus Titanium、GaN CCM 图腾柱无桥 PFC 和半桥 LLC(具有 LFU)参考设计。在整个框图中看到SPLL_1ph_SOGI的模块(实验4:闭合电压和电流环路PFC),如下图1所示,刚开始不理解是什么用途,后来查找各种资料并结合源代码进行理解,终于有了一些头绪。先把我做了注释的spll_1ph_sogi.h代码贴上(注释写得有些罗嗦,主要是为了让自己更好理解),后面结合相关文档详细分析下其实现原理,特别是系数计算。由于刚开始学习数字电源开发,错漏之处还望大家指正。
图1-包含SPLL模块的系统框架图
//#############################################################################
//
// FILE: spll_1ph_sogi.h
//
// TITLE: Orthogonal Signal Generator Software Phase Lock Loop (SPLL)
// for Single Phase Grid Module
//
//#############################################################################
// $TI Release: Software Phase Lock Loop Library v1.03.00.00 $
// $Release Date: Thu Dec 14 13:13:04 CST 2023 $
// $Copyright:
// Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
//
// ALL RIGHTS RESERVED
// $
//#############################################################################
#ifndef SPLL_1PH_SOGI_H
#define SPLL_1PH_SOGI_H
#ifdef __cplusplus
extern "C" {
#endif
//*****************************************************************************
//
//! \addtogroup SPLL_1PH_SOGI
//! @{
//
//*****************************************************************************
//
// Included Files
//
#include <stdint.h>
#ifndef __TMS320C28XX_CLA__
#include <math.h>
#else
#include <CLAmath.h>
#endif
//#############################################################################
//
// Macro Definitions
//
//#############################################################################
#ifndef C2000_IEEE754_TYPES
#define C2000_IEEE754_TYPES
#ifdef __TI_EABI__
typedef float float32_t;
typedef double float64_t;
#else // TI COFF
typedef float float32_t;
typedef long double float64_t;
#endif // __TI_EABI__
#endif // C2000_IEEE754_TYPES
//
// Typedefs
//
//! \brief Defines the SPLL_1PH_SOGI_OSG_COEFF structure
//!
typedef struct{
float32_t osg_k;
float32_t osg_x;
float32_t osg_y;
float32_t osg_b0;
float32_t osg_b2;
float32_t osg_a1;
float32_t osg_a2;
float32_t osg_qb0;
float32_t osg_qb1;
float32_t osg_qb2;
} SPLL_1PH_SOGI_OSG_COEFF;
//! \brief Defines the SPLL_1PH_SOGI_LPF_COEFF structure
//!
typedef struct{
float32_t b1;
float32_t b0;
} SPLL_1PH_SOGI_LPF_COEFF;
//! \brief Defines the Orthogonal Signal Generator SPLL_1PH_SOGI
//! structure
//!
//! \details The SPLL_1PH_SOGI can be used to generate the
//! orthogonal signal from the sensed single phase grid voltage
//! and use that information to provide phase of the grid voltage
//!
typedef struct{
float32_t u[3]; //!< AC input data buffer
float32_t osg_u[3]; //!< Orthogonal signal generator data buffer
float32_t osg_qu[3]; //!< Orthogonal signal generator quadrature data buffer
float32_t u_Q[2]; //!< Q-axis component
float32_t u_D[2]; //!< D-axis component
float32_t ylf[2]; //!< Loop filter data storage
float32_t fo; //!< Output frequency of PLL(Hz)
float32_t fn; //!< Nominal frequency (Hz)
float32_t theta; //!< Angle output (0-2*pi)
float32_t cosine; //!< Cosine value of the PLL angle
float32_t sine; //!< Sine value of the PLL angle
float32_t delta_t; //!< Inverse of the ISR rate at which module is called
SPLL_1PH_SOGI_OSG_COEFF osg_coeff; //!< Orthogonal signal generator coefficient
SPLL_1PH_SOGI_LPF_COEFF lpf_coeff; //!< Loop filter coeffcient structure
} SPLL_1PH_SOGI;
//! \brief Resets internal storage data of the module
//! \param *spll_obj The SPLL_1PH_SOGI structure pointer
//! \return None
//!
static inline void SPLL_1PH_SOGI_reset(SPLL_1PH_SOGI *spll_obj)
{
spll_obj->u[0]=(float32_t)(0.0);
spll_obj->u[1]=(float32_t)(0.0);
spll_obj->u[2]=(float32_t)(0.0);
spll_obj->osg_u[0]=(float32_t)(0.0);
spll_obj->osg_u[1]=(float32_t)(0.0);
spll_obj->osg_u[2]=(float32_t)(0.0);
spll_obj->osg_qu[0]=(float32_t)(0.0);
spll_obj->osg_qu[1]=(float32_t)(0.0);
spll_obj->osg_qu[2]=(float32_t)(0.0);
spll_obj->u_Q[0]=(float32_t)(0.0);
spll_obj->u_Q[1]=(float32_t)(0.0);
spll_obj->u_D[0]=(float32_t)(0.0);
spll_obj->u_D[1]=(float32_t)(0.0);
spll_obj->ylf[0]=(float32_t)(0.0);
spll_obj->ylf[1]=(float32_t)(0.0);
spll_obj->fo=(float32_t)(0.0);
spll_obj->theta=(float32_t)(0.0);
spll_obj->sine=(float32_t)(0.0);
spll_obj->cosine=(float32_t)(0.0);
}
//! \brief Calculates the SPLL_1PH_SOGI coefficient
//! \param *spll_obj The SPLL_1PH_SOGI structure
//! \return None
//!
static inline void SPLL_1PH_SOGI_coeff_calc(SPLL_1PH_SOGI *spll_obj)
{
/* 各系数赋值过程
* w = 角频率,2PI*频率,如果50Hz计算,则角频率为:50*2*PI
* x = 2*k*w*Ts;
y = w*Ts*w*Ts;
temp = 1/(x+y+4.0);
b0 = x*temp;
b2 = (-1.0)*b0;
a1 = (2.0)*(4.0-y)*temp;
a2 = (x-y-4)*temp;
qb0 = (k*y)*temp;
qb1 = qb0*(2.0);
qb2 = qb0;
请参考以下文章:https://www.cnblogs.com/swear/p/12682551.html
中的第7和第8个算式,H(d)和H(q)的离散表达式中各个系数的表达式,以便理解以下代码系数计算方式的来源
根据TI提供的官方文档,K值的选取决定了二阶积分器的频率选择,本应用应该选择小一些的K值,但过小会影响响应速度
* */
float32_t osgx,osgy,temp, wn;
wn= spll_obj->fn *(float32_t) 2.0f * (float32_t) 3.14159265f;//角频率
spll_obj->osg_coeff.osg_k=(float32_t)(0.5);//K系数初始值,默认0.5
osgx = (float32_t)(2.0f*0.5f*wn*spll_obj->delta_t);//x
spll_obj->osg_coeff.osg_x=(float32_t)(osgx);
osgy = (float32_t)(wn*spll_obj->delta_t*wn*spll_obj->delta_t);//y
spll_obj->osg_coeff.osg_y=(float32_t)(osgy);
temp = (float32_t)1.0/(osgx+osgy+4.0f);//temp
spll_obj->osg_coeff.osg_b0=((float32_t)osgx*temp);//b0, x * temp
spll_obj->osg_coeff.osg_b2=((float32_t)(-1.0f)*spll_obj->osg_coeff.osg_b0);//b2, (-1.0)*b0
spll_obj->osg_coeff.osg_a1=((float32_t)(2.0*(4.0f-osgy))*temp);//a1, (2.0)*(4.0-y)*temp
spll_obj->osg_coeff.osg_a2=((float32_t)(osgx-osgy-4)*temp);//a2, (x-y-4)*temp
spll_obj->osg_coeff.osg_qb0=((float32_t)(0.5f*osgy)*temp);//qb0, (k*y)*temp, k = 0.5
spll_obj->osg_coeff.osg_qb1=(spll_obj->osg_coeff.osg_qb0*(float32_t)(2.0));//qb1, qb0*(2.0)
spll_obj->osg_coeff.osg_qb2=spll_obj->osg_coeff.osg_qb0;//qb2, = qb0
}
//! \brief Configures the SPLL_1PH_SOGI module
//! \param *spll_obj The SPLL_1PH_SOGI structure
//! \param acFreq Nominal AC frequency for the SPLL Module
//! \param isrFrequency Frequency at which SPLL module is run
//! \param lpf_b0 B0 coefficient of LPF of SPLL
//! \param lpf_b1 B1 coefficient of LPF of SPLL
//! \return None
//!
static inline void SPLL_1PH_SOGI_config(SPLL_1PH_SOGI *spll_obj,
float32_t acFreq,
float32_t isrFrequency,
float32_t lpf_b0,
float32_t lpf_b1)
{
spll_obj->fn=acFreq;
spll_obj->delta_t=((1.0f)/isrFrequency);//SPLL调用频率,100KHz
SPLL_1PH_SOGI_coeff_calc(spll_obj);
//=====================================================================================================================
//根据PI控制器离散形式的表达式(离散的意思就是将原来的连续信号变成按周期执行,例如:SPLL的执行频率是100K = 0.00001秒)
//PI的拉普拉斯变换形式是:ylf(s)/ynotch(s) = Kp + Ki/s
//使用双线性变换得到Z域离散表达式:ylf(z)/ynotch(z) = (B0 + B1*z^(-1)) / (1 - z^(-1))
//系数B0 = (2*Kp + Ki*T)/2, B1 = - (2*Kp - Ki*T)/2,
//例如:使用30ms的稳定时间(应该就是从误差值到Q值为0),5% 的误差带以及 0.7 的阻尼比,可获得 158.6859 的固有频率;然后通过回代,可得到
//Kp = 222.1603 和 Ki = 25181.22,T 在前面我们已经说了就是离散时间,也就是0.00001秒。将这些值回代至数字环路滤波器系数中:
//B0 = (2*Kp + Ki*T)/2 = (2*222.1603 + 25181.22*0.00001)/2 = 222.2862061
//B1 = -(2*Kp - Ki*T)/2 = (2*222.1603 - 25181.22*0.00001)/2 = -222.0343939
//======================================== 固有/自然频率(无阻尼振荡频率)的计算方式:===========================================
/*
* 1. 设需要稳定的时间为Ts = 30ms = 0.03s, 5%的误差带,即∂ = 0.05,阻尼比ζ = 0.7
*
* 2. 根据通用二阶等式的阶跃响应公式可推出:
*
* ∂ = ce^(-σTs),其中c = Wn/Wd, σ = ζWn(衰减指数), Wd = √(1-ζ^2) * Wn,Wn表示系统固有频率,即无阻尼自由振荡角频率,Wd表示有阻尼频率
*
*
* 3. 将各项系数代入等式:∂ = ce^(-σTs),即 0.05 = Wn/√(1-0.49) * Wn * e^(-0.7*Wn*0.03),经过化简得到
* 0.035707 = e^(-0.021*Wn),两边同时取以自然数为底的对数,则有:ln(0.035707) = -0.021*Wn, 左边通过计算器得为-3.3324085,从而求得到:
*
* Wn = 158.6859
*
* 或者也可通过其他数据得到: Ts = (1/σ)*ln(c/∂),其实也是上述公式的变形而已
*
* Kp和Ki的计算请参考TI提供的excel文档计算器,其计算值和一个Ti有关,Ti = 2*ζ/Wn = 0.0088224599
* 关于Ti的计算可参考TI的文档中的说明:The natural frequency and the damping ration of the linearized PLL are given as:
* Wn = √ ( Vgrid*Kp )
* ζ = √ ( Vgrid*Ti*Kp/4 )
*
* 合并上述两个算式可以求出Ti与Vgrid和Kp无关的表达式:Ti = 2*ζ/Wn
*
* Kp = Wn * Wn * Ti = 222.16026
* Ki = Kp/Ti = 25181.215
*
* */
//======================================================================================================================
spll_obj->lpf_coeff.b0=lpf_b0;//222.2862
spll_obj->lpf_coeff.b1=lpf_b1;//-222.034
}
//! \brief Run the SPLL_1PH_SOGI module
//! \param *spll_obj The SPLL_1PH_SOGI structure pointer
//! \param acValue AC grid voltage in per unit (pu)
//! \return None
//!
static inline void SPLL_1PH_SOGI_run(SPLL_1PH_SOGI *spll_obj,
float32_t acValue)
{
// Update the spll_obj->u[0] with the grid value
spll_obj->u[0]=acValue;
//
// Orthogonal Signal Generator
//
// ===================== 核心差分方程:数次原始输入+数次滤波信号的线性组合 ======================
//V.alpha_filt = b0*V.alpha + b2*V.alpha_Z2 + a1*V.alpha_filt_Z1 + a2*V.alpha_filt_Z2;
//参考离散序列:Uo(k) − a1Uo(k−1) − a2Uo(k−2) = b0Ui(k) + b2Ui(k−2)
//离散序列的获取是在MATLAB中根据传递函数来生成的(也就是从s域转换到z域),如下:
//同相传递函数: Hd_s = k*Wn*s/(s^2+k*Wn*s+Wn^2);
//MATLAB中转换为离散形式: Hd_z = c2d(Hd_s,Ts,'tustin')
//=====================================================================================
spll_obj->osg_u[0]=(spll_obj->osg_coeff.osg_b0*
(spll_obj->u[0]-spll_obj->u[2])) +
(spll_obj->osg_coeff.osg_a1*spll_obj->osg_u[1]) +
(spll_obj->osg_coeff.osg_a2*spll_obj->osg_u[2]);
spll_obj->osg_u[2]=spll_obj->osg_u[1];//保存历史记录值
spll_obj->osg_u[1]=spll_obj->osg_u[0];
//==================================================================================================
//u[0],u[1],u[2]是多次的原始AC信号
//参考离散序列:Uqo(k) − a1Uqo(k−1) − a2Uqo(k−2) = qb0Ui(k) + qb1Ui(k−1) + qb2Ui(k−2)
//离散序列的获取是在MATLAB中根据传递函数来生成的(也就是从s域转换到z域),如下:
//正交信号传递函数: Hq_s = k*Wn^2/(s^2+k*Wn*s+Wn^2);
//MATLAB中转换为离散形式: Hq_z = c2d(Hq_s,Ts,'tustin')
//==================================================================================================
spll_obj->osg_qu[0]=(spll_obj->osg_coeff.osg_qb0*spll_obj->u[0]) +
(spll_obj->osg_coeff.osg_qb1*spll_obj->u[1]) +
(spll_obj->osg_coeff.osg_qb2*spll_obj->u[2]) +
(spll_obj->osg_coeff.osg_a1*spll_obj->osg_qu[1]) +
(spll_obj->osg_coeff.osg_a2*spll_obj->osg_qu[2]);
spll_obj->osg_qu[2]=spll_obj->osg_qu[1];//保存历史记录值
spll_obj->osg_qu[1]=spll_obj->osg_qu[0];
spll_obj->u[2]=spll_obj->u[1];
spll_obj->u[1]=spll_obj->u[0];
//
// Park Transform from alpha beta to d-q axis
// 详见派克变换将alpha beta转换到dq轴上的公式
//
/* =========== 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];
* */
//===================================================================================
//程序最后一步通过θ生成的spll_obj->sine和spll_obj->cosine又会被回代到Park Transform变换公式中
spll_obj->u_Q[0]=(spll_obj->cosine*spll_obj->osg_u[0]) +
(spll_obj->sine*spll_obj->osg_qu[0]);
spll_obj->u_D[0]=(spll_obj->cosine*spll_obj->osg_qu[0]) -
(spll_obj->sine*spll_obj->osg_u[0]);
//==================================================================================
//==================================================================================
//
// Loop Filter 环路滤波器,也就是PI控制器
// 环路滤波器就是积分器,将输入的交流信号积分成直流信号,最后输出VCO的控制电压信号,VCO最后控制频差
// 参照TI的技术文档,Loop Filter的算法:
// The loop filter or the PI is implemented as a digital controller with the equation below:
// ylf[0] = ylf[n-1]*A1 + ynotch[n]*B0 + ynotch[n-1]*B1
// 这里只用到u_Q是因为最终要判断该值是否趋近于0,如果是就表示已锁相,否则就没有
//
spll_obj->ylf[0]=spll_obj->ylf[1] +
(spll_obj->lpf_coeff.b0*spll_obj->u_Q[0]) + //b0*ynotch[n]
(spll_obj->lpf_coeff.b1*spll_obj->u_Q[1]);//b1*ynotch[n-1]
spll_obj->ylf[1]=spll_obj->ylf[0];
spll_obj->u_Q[1]=spll_obj->u_Q[0];
//==================================================================================
//========================================================================================
// VCO 压控振荡器
//
spll_obj->fo=spll_obj->fn+spll_obj->ylf[0];
//由dq轴的角速度的积分得出相位θ
//spll_obj->fn : 实时的AC电网电压
//spll_obj->fo : PLL的输出频率
//spll_obj->delta_t : SPLL的调用频率,默认是100K,这里取倒数
//spll_obj->theta : d轴与两相静止坐标系中alpha轴的夹角θ表示dq坐标系当前的位置
// 假设DQ坐标系在初始位置时,d轴与alpha轴重合,则θ = 0
spll_obj->theta=spll_obj->theta + (spll_obj->fo*spll_obj->delta_t)* //累加,也就是积分得到相位θ
(float32_t)(2.0*3.1415926f);//2*PI
//最后反馈的是相位,通过使输出相位θ控制在目标值wt,最后达到频率相等
if(spll_obj->theta>(float32_t)(2.0*3.1415926f))
{
spll_obj->theta=spll_obj->theta - (float32_t)(2.0*3.1415926f);//将theta限制在0-2pi范围内
//spll_obj->theta=0;
}
spll_obj->sine=(float32_t)sinf(spll_obj->theta);
spll_obj->cosine=(float32_t)cosf(spll_obj->theta);//得出一个Vpll=cosθ的波形一直同步电网
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
#ifdef __cplusplus
}
#endif // extern "C"
#endif // end of _SPLL_1PH_SOGI_H_ definition
//
// End of File
//
SPLL主要用到了正交信号生成器,而这个信号的生成使用二阶广义积分器,也就是SOGI,其框图如图2所示。
图2-SOGI框图
关于SOGI的介绍可参考以下博文:
连续函数离散化-以SOGI为例 - Siwei_Yang - 博客园 (cnblogs.com)
单相并网逆变器学习记录-------------SOGI-PLL锁相环_sogi锁相环-CSDN博客
第一篇博文详细讲述了SOGI的传递函数及其离散形式和系数计算,第二篇博文详细介绍了DQ坐标系,很好理解。这两篇博文对我理解源代码起了非常大的作用,在此表示感谢。
我的程序注释就是要理解:系统在初始化调用SPLL中的static inline void SPLL_1PH_SOGI_config函数时系数的来源,为什么LPF也就是PI控制器中lpf_b0的值设置为222.2862而lpf_b1的值设置为-222.034?如图3所示,为什么函数SPLL_1PH_SOGI_coeff_calc中关于SOGI的相关系数的计算是如图4所示的方法?只有从根本上理解了这些才能在条件变化时也能知道怎么计算系数。
图3-Loop Filter系数设置
图4-SOGI系数计算方法
先说LPF滤波/PI控制器的系数计算部分。先看下TI官方文档的中关于PI控制器离散化实现的说明,如图5所示。其中有一个红色部分的错误,就是自然对数求值括号中应该是c / ∂,而不是c / σ,∂就是那个误差带,值为5%,难怪刚开始我怎么算结果都是一个负数。根据红色框部分提供的公式及已知变量,可以算出Wn(无阻尼振荡频率或者文档所说的自然/固有频率)。这里稳定时间Ts = 0.03s,∂=0.05,阻尼比 ζ = 0.7,套进公式可得:
1. ∂ = ce^(-σTs)
2. 0.05 = Wn/√(1-0.49) * Wn * e^(-0.7*Wn*0.03),化简得到
3. 0.035707 = e^(-0.021*Wn)
4. 两边同时取以自然数为底的对数,右边消除e,则有:ln(0.035707) = -0.021*Wn
5. 左边通过计算器得到-3.3324085,从而求得到:Wn = 158.6859
在离散形式下如果知道Kp和Ki及T(采样周期,在主程序ISR中的调用频率是100KHz),两个系数B0和B1可以通过图5底部的公式计算出来。文档说T=50KHz的计算出来的结果B0=223.4149,B1=-220.901,但是实际推算T=10KHz才会得到如文档所说的结果,这应该也是文档中的一个错误。如果T=100K,则刚好是我们程序初始化时的值,即:B0=222.2862,B1=-222.034。但是Kp和Ki是怎么来的呢?我找到了一个TI提供的SPLL相关系数计算的excel文档(安装目录:\c2000-DigitalPower-SDK\C2000Ware_DigitalPower_SDK_5_01_00_00\solutions\tida_01606\hardware),主界面如图6所示,可以看到Kp = Wn * Wn * Ti,Ti出现在图7所示的内容中,猜想应该是积分时间,有知道的朋友麻烦解释下。
图5-TI官方文档对PI离散化的说明
图6-TI提供的系数计算excel文档
图7-Ti与阻尼系数及固有频率的关系
对两式进行合并运算很容易得到Ti = 2*ζ / Wn,这样就可以理解excel表中Ti值的来源,并且在知道Wn的情况下计算Kp值了,同样Ki的值也可以确定,Ki = Kp / Ti。
再看SOGI部分源程序的系数是怎么确定的。由前面推荐的博文我们可以知道同相和正交的离散形式表达,如图8所示(通过使用变量 x = 2KWnTs, y = (WnTs)^2),所以在源程序的SPLL_1PH_SOGI_coeff_calc函数中有如下语句:
osgx = (float32_t)(2.0f*0.5f*wn*spll_obj->delta_t);
osgy = (float32_t)(wn*spll_obj->delta_t*wn*spll_obj->delta_t);
其中osgx就相当于x,osgy相当于y,K值设置为0.5,spll_obj->delta_t就是SPLL模块的执行频率100KHz,这里是周期 = 0.00001秒。对于同相函数离散形式的系数b0, b2, a1, a2与x, y的关系,观察离散形式表达式左右两端就很清楚了:b0 = x / (x+y+4), b2 = -x / (x+y+4), a1 = 2(4-y) / (x+y+4), a2 = (x-y-4) / (x+y+4),所以在源程序里就有如下代码(其中变量temp = 1 /( x+y+4)):
temp = (float32_t)1.0/(osgx+osgy+4.0f);//temp
spll_obj->osg_coeff.osg_b0=((float32_t)osgx*temp);//b0, x * temp
spll_obj->osg_coeff.osg_b2=((float32_t)(-1.0f)*spll_obj->osg_coeff.osg_b0);//b2, (-1.0)*b0
spll_obj->osg_coeff.osg_a1=((float32_t)(2.0*(4.0f-osgy))*temp);//a1, (2.0)*(4.0-y)*temp
spll_obj->osg_coeff.osg_a2=((float32_t)(osgx-osgy-4)*temp);//a2, (x-y-4)*temp
这样理解代码就容易了,对于正交的离散形式系数的计算方法也是同样方法。
图8-同相和正交函数离散形式
得到了同相和正交函数的离散形式,我们就可以得到输入和输出之间的关系并得到序列方程,如图9所示,对于SPLL_1PH_SOGI_run函数中的Orthogonal Signal Generator代码部分就容易理解了。
//参考离散序列:Uo(k) − a1Uo(k−1) − a2Uo(k−2) = b0Ui(k) + b2Ui(k−2)
spll_obj->osg_u[0]=(spll_obj->osg_coeff.osg_b0*
(spll_obj->u[0]-spll_obj->u[2])) +
(spll_obj->osg_coeff.osg_a1*spll_obj->osg_u[1]) +
(spll_obj->osg_coeff.osg_a2*spll_obj->osg_u[2]);
spll_obj->osg_u[2]=spll_obj->osg_u[1];
spll_obj->osg_u[1]=spll_obj->osg_u[0];
//参考离散序列:Uqo(k) − a1Uqo(k−1) − a2Uqo(k−2) = qb0Ui(k) + qb1Ui(k−1) + qb2Ui(k−2)
spll_obj->osg_qu[0]=(spll_obj->osg_coeff.osg_qb0*spll_obj->u[0]) +
(spll_obj->osg_coeff.osg_qb1*spll_obj->u[1]) +
(spll_obj->osg_coeff.osg_qb2*spll_obj->u[2]) +
(spll_obj->osg_coeff.osg_a1*spll_obj->osg_qu[1]) +
(spll_obj->osg_coeff.osg_a2*spll_obj->osg_qu[2]);
spll_obj->osg_qu[2]=spll_obj->osg_qu[1];
spll_obj->osg_qu[1]=spll_obj->osg_qu[0];
图9-序列方程表达式
关于SPLL_1PH_SOGI_run函数中的Park变换部分,源程序如下:
spll_obj->u_Q[0]=(spll_obj->cosine*spll_obj->osg_u[0]) +
(spll_obj->sine*spll_obj->osg_qu[0]);
spll_obj->u_D[0]=(spll_obj->cosine*spll_obj->osg_qu[0]) -
(spll_obj->sine*spll_obj->osg_u[0]);
我总觉得u_Q[0]和u_D[0]赋值是不是搞反了?还是我对代码理解错误,有知道的朋友还望指点一下。
小结:
在理解源程序时,首先要看下程序的框架图,它是由哪些模块组成的,各模块之间的输入输出关系。对于特定的模块,如本文所讨论的SPLL的SOGI,了解了其原理再来理解源代码就容易很多。记得刚开始学习单片机的时候,公司要用51单片机做一个邮件发送程序,当时我用的是uIP协议栈,也是先理解SMTP协议再来看uIP提供的示例代码,最后很顺利地完成开发。
为了应对今后公司大概率要做数字电源,我向公司申请购买了一套TI开发套件,是关于BUCK电路的数字实现,然后就开始学习电路的传递函数、拉普拉斯变换、各种滤波算法、微积分、自动化原理等等,由于基础不好,所以学习进度很慢,但是每当学习到一样新知识,特别是了解其实现原理后对自己就有特别大的鼓励,使自己不断地学习、不断地超越自我。