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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/774038.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件测试面试题集(含答案)

软件测试面试题集一、Bug基本要素 缺陷ID&#xff0c;状态&#xff0c;类型&#xff0c;所属项目&#xff0c;所属模块&#xff0c;缺陷提交时间&#xff0c;缺陷提交人&#xff08;检测者&#xff09;&#xff0c;严重程度&#xff0c;优先级别&#xff0c;缺陷描述信息&#…

【TS】TypeScript 联合类型详解:解锁更灵活的类型系统

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 TypeScript 联合类型详解&#xff1a;解锁更灵活的类型系统一、联合类型的定义二…

一站式采购!麒麟信安CentOS安全加固套件上架华为云云商店

近日&#xff0c;麒麟信安CentOS安全加固套件正式上架华为云云商店&#xff0c;用户可登录华为云官网搜索“CentOS安全加固”直接采购&#xff0c;一站式获取所需资源。 麒麟信安CentOS安全加固套件已上架华为云 https://marketplace.huaweicloud.com/contents/9fe76553-8d87-…

后端部署Jar包 | 启动失败系列问题(图解-BuiId,Maven)

目录 项目的构建 打包前的准备 合理配置pox.xml文件 Build 打包方式 Maven打包方式 Jar包部署 测试后端接口 项目的构建 我的项目是SpringBoot2脚手架 先准备一个相对于的数据库依赖 数据库的任意库 Yaml配置后 才能正常在IDEA中跑起来 打包前的准备 合理配置pox.xm…

推荐的一键下载1688高保真原图信息

图片在电商中扮演着至关重要的角色。高质量的商品图片能够直观展示产品特性&#xff0c;吸引消费者注意力&#xff0c;提升购买欲望。良好的视觉呈现还能增强品牌形象&#xff0c;提高转化率。此外&#xff0c;图片是跨语言的沟通方式&#xff0c;能够克服语言障碍&#xff0c;…

linux——小细节(Makefile)(gdb)

一、makefile a.out:main.c func.cgcc main.c func.cclean:rm a.out a.out:main.c func.cgcc $^ -o $clean:rm a.out SRCmain.c func.c OBJa.out CCgcc FLAG -g -lpthread $(OBJ):$(SRC)$(CC) $(SRC) $(FLAG)clean:rm $(OBJ) 二、gdb

快速傅里叶变换(Fast Fourier Transform)

快速算法&#xff08;FFT&#xff09;&#xff0c;即快速傅里叶变换&#xff08;Fast Fourier Transform&#xff09;&#xff0c;是一种用于计算离散傅里叶变换&#xff08;DFT&#xff09;及其逆变换的高效算法。FFT算法由J.W.库利和T.W.图基于1965年提出&#xff0c;显著减少…

7-google::protobuf::io命名空间下常用的C++ API----zero_copy_stream_impl.h

一、protobuf输入输出文件流C API总览 二、经常会用到的API

昇思25天学习打卡营第12天|MindSpore-基于MobileNetv2的垃圾分类

基于MobileNetv2的垃圾分类 主要介绍垃圾分类代码开发的方法。通过读取本地图像数据作为输入,对图像中的垃圾物体进行检测,并且将检测结果图片保存到文件中。 1、实验目的 了解熟悉垃圾分类应用代码的编写(Python语言);了解Linux操作系统的基本使用;掌握atc命令进行模型…

每日Attention学习8——Rectangular self-Calibration Attention

模块出处 [ECCV 24] [link] [code] Context-Guided Spatial Feature Reconstruction for Efficient Semantic Segmentation 模块名称 Rectangular self-Calibration Attention (RCA) 模块作用 空间注意力 模块结构 模块代码 import torch import torch.nn as nn import tor…

Redis基础教程(十四):Redis连接

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

Turborepo简易教程

参考官网&#xff1a;https://turbo.build/repo/docs 开始 安装全新的项目 pnpm dlx create-turbolatest测试应用包含&#xff1a; 两个可部署的应用三个共享库 运行&#xff1a; pnpm install pnpm dev会启动两个应用web(http://localhost:3000/)、docs(http://localhost…

程序员,去哪个城市工作更幸福?

深漂、沪漂、京漂、杭漂……又是一年毕业季&#xff0c;作为CS专业or新手程序员会选择什么城市工作呢&#xff1f;希望这篇文章给各位一些参考。 根据拉勾招聘大数据研究院的数据显示&#xff0c;超六成程序员集中在一线城市&#xff0c;其中北京19%&#xff0c;深圳16%&#x…

【遇坑笔记】Node.js 开发环境与配置 Visual Studio Code

【遇坑笔记】Node.js 开发环境与配置 Visual Studio Code 前言node.js开发环境配置解决pnpm 不是内部或外部命令的问题&#xff08;pnpm安装教程&#xff09;解决 pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本。 vscode 插件开…

汇川H5U小型PLC不用写程序测试EC总线电机

目录 新建工程添加EtherCAT组态添加运动控制轴仿真测试 新建工程 新建一个H5U工程&#xff0c;不使用临时工程 系列选择H5U即可 添加EtherCAT组态 这里在EC总线中添加了一个汇川660的伺服 驱动参数使用默认 添加运动控制轴 新建一个轴Axis_0 将新建的轴和EC组态的660驱动…

中国1km高分辨率高质量逐年近地表CO数据集(2013-2022年)

该数据为中国高分辨率高质量逐年CO数据集&#xff0c;该数据集主要的空间范围覆盖整个中国&#xff0c;其中内容包括中国1km高分辨率高质量逐年CO数据集(2013-2022年)。时间分辨率为年&#xff0c;单位为mg/m3&#xff0c;数据以(.nc/.tif)格式进行存储。

解决 npm intasll 安装报错 Error: EPERM: operation not permitted

Node.js安装及环境配置完成之后 npm install express -g 安装全局的模块报错提示没有权限operation not permitted mkdir 错误编号4048&#xff1a; 其原因是当前用户操作该目录权限不足&#xff0c;当以管理员身份运行cmd&#xff0c;再执行npm install express -g 是不会报权…

使用 AlphaZero 和 Tabu 搜索查找越来越大的极值图

使用 AlphaZero 和 Tabu 搜索查找越来越大的极值图 AlphaZero 方法最佳研究&#xff08;第1部分&#xff09; 文章目录 一、说明二、引言三、预备知识四、方法4.1 AlphaZero4.2 禁忌搜索 五、实验与结果六、讨论七、附录A 一个例子B 问题背景 一、说明 人工智能的树和图的检索问…

Solution

(解决方案)可行性研究报告暨设计方案-zengwenfeng.doc 基本上都要300-500多页&#xff0c;大型【纯软件】&#xff0c;县级0-200万&#xff0c;市级项目500-1500万不等&#xff0c;省部级1000-10000万不等都有。本例为过往已完成项目案例目录结构。搞方案都要准备1-3个月呢。所…

Windows搭建本地对象存储服务MinIO并且使用springboot整合

开发文档&#xff1a; MinIO Windows中文文档 MinIO Object Storage for Windows &#xff08;英文文档&#xff09; 1、准备工作 准备一个空的文件夹&#xff0c;用来存放minio相关的内容&#xff1b; 这里是在D盘创建一个minio的文件夹&#xff1b; 后续所有跟MinIO相关…