SPLL单相软件锁相环相关源代码理解-SOGI及PI系数计算

最近在学习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电路的数字实现,然后就开始学习电路的传递函数、拉普拉斯变换、各种滤波算法、微积分、自动化原理等等,由于基础不好,所以学习进度很慢,但是每当学习到一样新知识,特别是了解其实现原理后对自己就有特别大的鼓励,使自己不断地学习、不断地超越自我。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值