This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Phase Locked Loop (PLL) for grid connected output

Other Parts Discussed in Thread: CONTROLSUITE, TMS320F28035

Dear all,

anyone knows if there is PLL algorithm that we may use directly?

thanks a lot!

Regards,

Felix

  • A generic PLL can be found online ...Google will offer a number of examples ... however, the IP is in making the PLL robust enough for real world application. I doubt you will find those real-world PLL implementations as free example or download. By the way, are you looking for a three phase or single phase application?

  • Felix,

     

    I have an implementation of SPLL that i am happy to share, you would need to send me a message with your affiliation through the community,

    You can friend me to send me an email, 

     

    regards

    Manish Bhardwaj

  • Just to add the PLL is a single phase PLL, it would provide you a structure to code the PLL you may have to tweak the PLL to get the frequency error within the range depending on the power rating of your grid connect inverter,

    -Manish

  • Hello Manish,

    I need such an implementation example too.

    I am working on a 3-phase grid connected solar inverter project and I need to syncronise the inverter output to the grid. I have tried simply zero crossing feedback from grid for syncronisation, but THD is too high in this case.

    I send you a friend request. Could you share your SPLL implementation with me as well.

    Regards,

    Kerem

  • Hello Kerem .. Zero crossing detection method is simple but may not be sufficient in many applications. One possible solution is to use Clark /Park transformations in addition zero crossing information to have a more robust implementation. You will also have to watch for line noise, line voltage unbalance and faults.

     I am also interested to know more about TI implementation ... please post the link, if available, for download.

  • Hello  Manish,

    I am also have this kind of problems in the implemention of SPLL, could you share you PLL implement (single phase)with me as well.

    Thanks!

    Danny

     

  • Dear all,

    The PLL method is now available in ControlSUITE both in fixed and IQ format,

    Please check,

    ControlSUITE\libs\app_libs\solar\

    Regards

    Manish Bhardwaj

  • Can you tell me how to determine the coefficients for 2P2Z Notch Filter at different sample rate, say 10e-6s. Thanks.

    Tony Jiang

  • You can use band stop filter to closely approximate the notch

    for example in Matlab coefficients can be got from

    [B,A]=butter(1,[95*2/10000 105*2/10000],'stop')

    Regards

    Manish Bhardwaj

  • Manish,

    As per the document (pdf) in ControlSUITE\libs\app_libs\solar\.. It says the PI takes care of the system dynamics. And no more we have to take concentrate on the  filtering capabilities of PI. But in the Code (provided as Header file), the PLL is created with the PI, considering as a Low pass filter... and moreover a notch filter is also use.. Could please clarify me the use of two filters (LPF and Notch filters) in the code.

    And also let me know, whether this PLL work for a polluted grid. Grid containing Third, fifth and some EMI etc...)

    Thanks in Advance.

  • Angamuthu,

    Classical PLL consists of PD, LF (PI) , VCO. If you look at the small signal model of a PLL the BW of the PLL is determied by how you tune the LF(PI). The small signal model assumes the 2w frequency is high and will be cancelled out by the low pass characteristics of the LF(which is tuned for the BW and not to filter out the 2w).

    For grid tied applications the 2w is low enough that the low pass characteristics of the system cannot be banked upon alone, Hence a notch filter was added to  cancel the 2w. LPF -. loop filter in some cases , sorry for the confusion. 

    The PLL is resilient to polluted grid and harmonics,

    What are your affiliations?

    Regards

    Manish Bhardwaj

  • hi  ,

          From  Solar HV DC-AC Kit User Guide_Rev1.0.pdf ,It seems the project has an anti-islanding function,But I can't find related code in .

    ...:\TI\controlSUITE\development_kits\HV_SOLAR_DC_AC_v1.0\SolarHv_DCAC_PiccoloB_Rev_02 

    Do you know when the related code will be released?    Thanks!

  • Hello Manish,

    I have read some post you have done, seems that you have work a lot with SPLL.h, maybe you can help me working on my code.

    I need to create another theta that will take an user input to change the phase (in degrees) of my system. Do you have any hints for me??

     

  • WHat is the application you are trying to write the PLL for? single phase? 3 phase... grid connected?

  • I am using a single phase. I  have actually two solar kits, one of the is the grid simulation which will be feeding into the other's battery.  Anyhow, that will be the long run, now I am just working on the PLL lock an input phase .

    I am working on the float file.

  • I am trying give the user the faculty to choose the degree to lock the phase at. 

  • Sofia,

    The PLL will lock to the Grid Phase,

    Now in some cases you may want to induce a phase advance or a delay from the locked phase?, is this what you want to do?

  • Yes Manish, i want to induce the the phase.
  • Sofia,

    If you study the code the SPLL also gives you the angle of the grid,

    So to get a sinusoidal wave with a phase advance / delay you will have to do the following

    ; pseudo code...

    theta_new=spll1.theta+phase_diff;

    and to get the new sine and cosine value

    sin_phasediff=_IQsin(theta_new);

    cos_phasediff=_IQcos(theta_new);

  • Dear Manish,

    I totally agree with you, but the result is not sinusoidal.

    My code is the follow:

    theta = (long)((long)(spll1.theta[0])>>3)-_IQ15(phase_diff);

    sen_theta = _IQ15sin(theta);

    Can you help me?

    Thank you for your kindness!

  • Michele,

    There is an error in the theta calculation of the spll block,

    Please refer to the below post

    http://e2e.ti.com/support/microcontrollers/tms320c2000_32-bit_real-time_mcus/f/171/p/164077/652983.aspx#652983

    Maybe this will correct your problem , the library version 1.1 will fix this,

    Regards

    Manish Bhardwaj

  • I can't find the C28x Solar Library v1.1!

    Can you  send me the link?

    I add:

    spll_obj->theta[0]=spll_obj->theta[1]+(spll_obj->wo*(0.00000795));

    in my code but I have this error:

    Severity and Description Path Resource Location Creation Time Id
    identifier "spll_obj" is undefined AsymmetricPWM AsymmetricPWM-Main.c line 333 1338825099421 5991

     

    Thanks

  • Well i meant that this line of code will be fixed whenever we update the library, till then you can just copy paste the line and it should work,

  • Ok Manish, you're right!

    I paste the line that you recommended, but the wave is not sinusoidal.

    I send you my spll_1ph, can you correct this ?

    Thanks for your kindness

    #ifndef

    _SPLL_1ph_H_

    #define

    _SPLL_1ph_H_

    #define

    SPLL_Q _IQ21

    #define

    SPLL_Qmpy _IQ21mpy

    typedef

    struct{

    int32 B2_notch;

    int32 B1_notch;

    int32 B0_notch;

    int32 A2_notch;

    int32 A1_notch;

    }SPLL_NOTCH_COEFF;

    typedef

    struct{

    int32 B1_lf;

    int32 B0_lf;

    int32 A1_lf;

    }SPLL_LPF_COEFF;

    typedef

    struct{

    int32 AC_input;

    int32 theta[2];

    int32 cos[2];

    int32 sin[2];

    int32 wo;

    int32 wn;

    SPLL_NOTCH_COEFF notch_coeff;

    SPLL_LPF_COEFF lpf_coeff;

    int32 Upd[3];

    int32 ynotch[3];

    int32 ylf[2];

    int32 delta_t;

    }SPLL_1ph;

     

    void

    SPLL_1ph_init(int Grid_freq, int DELTA_T, SPLL_1ph *spll);

    inline

    voidSPLL_1ph_run(SPLL_1ph *spll1);

    void

    SPLL_1ph_init(int Grid_freq, intDELTA_T, SPLL_1ph *spll_obj)

    {

    spll_obj->Upd[0]=SPLL_Q(0.0);

    spll_obj->Upd[1]=SPLL_Q(0.0);

    spll_obj->Upd[2]=SPLL_Q(0.0);

    spll_obj->ynotch[0]=SPLL_Q(0.0);

    spll_obj->ynotch[1]=SPLL_Q(0.0);

    spll_obj->ynotch[2]=SPLL_Q(0.0);

    spll_obj->ylf[0]=SPLL_Q(0.0);

    spll_obj->ylf[1]=SPLL_Q(0.0);

    spll_obj->sin[0]=SPLL_Q(0.0);

    spll_obj->sin[1]=SPLL_Q(0.0);

    spll_obj->cos[0]=SPLL_Q(0.999);

    spll_obj->cos[1]=SPLL_Q(0.999);

    spll_obj->theta[0]=SPLL_Q(0.0);

    spll_obj->theta[1]=SPLL_Q(0.0);

    spll_obj->wn=SPLL_Q(2*3.14*Grid_freq);

    // coefficients for the notch filter

    // Grid Frequency 50Hz

    if(Grid_freq==50)

    {

    spll_obj->notch_coeff.B2_notch=SPLL_Q(0.972);

    spll_obj->notch_coeff.B1_notch=SPLL_Q(-1.9402);

    spll_obj->notch_coeff.B0_notch=SPLL_Q(0.972);

    spll_obj->notch_coeff.A2_notch=SPLL_Q(0.944);

    spll_obj->notch_coeff.A1_notch=SPLL_Q(-1.9402);

    }

    // Grid Frequency 60Hz

    else if (Grid_freq==60)

    {

    spll_obj->notch_coeff.B2_notch=SPLL_Q(0.9969);

    spll_obj->notch_coeff.B1_notch=SPLL_Q(-1.9923);

    spll_obj->notch_coeff.B0_notch=SPLL_Q(0.9969);

    spll_obj->notch_coeff.A2_notch=SPLL_Q(0.9937);

    spll_obj->notch_coeff.A1_notch=SPLL_Q(-1.9923);

    }

    //coefficients for the loop filter

    spll_obj->lpf_coeff.B1_lf=SPLL_Q(-247.8);

    spll_obj->lpf_coeff.B0_lf=SPLL_Q(250.0);

    spll_obj->lpf_coeff.A1_lf=SPLL_Q(-1.0);

    spll_obj->delta_t=DELTA_T;

    }

     

     

    inline

    voidSPLL_1ph_run(SPLL_1ph *spll_obj)

    {

    //-------------------//

    // Phase Detect //

    //-------------------//

    spll_obj->Upd[0]=SPLL_Qmpy(spll_obj->AC_input,spll_obj->cos[1]);

    //-------------------//

    //Notch filter structure//

    //-------------------//

    spll_obj->ynotch[0]=-SPLL_Qmpy(spll_obj->notch_coeff.A1_notch,spll_obj->ynotch[1])-SPLL_Qmpy(spll_obj->notch_coeff.A2_notch,spll_obj->ynotch[2])+SPLL_Qmpy(spll_obj->notch_coeff.B0_notch,spll_obj->Upd[0])+SPLL_Qmpy(spll_obj->notch_coeff.B1_notch,spll_obj->Upd[1])+SPLL_Qmpy(spll_obj->notch_coeff.B2_notch,spll_obj->Upd[2]);

    // update the Upd array for future

    spll_obj->Upd[2]=spll_obj->Upd[1];

    spll_obj->Upd[1]=spll_obj->Upd[0];

    //---------------------------//

    // PI loop filter //

    //---------------------------//

    spll_obj->ylf[0]=-SPLL_Qmpy(spll_obj->lpf_coeff.A1_lf,spll_obj->ylf[1])+SPLL_Qmpy(spll_obj->lpf_coeff.B0_lf,spll_obj->ynotch[0])+SPLL_Qmpy(spll_obj->lpf_coeff.B1_lf,spll_obj->ynotch[1]);

    //update array for future use

    spll_obj->ynotch[2]=spll_obj->ynotch[1];

    spll_obj->ynotch[1]=spll_obj->ynotch[0];

    spll_obj->ylf[1]=spll_obj->ylf[0];

    //------------------//

    // VCO //

    //------------------//

    spll_obj->wo=spll_obj->wn+spll_obj->ylf[0];

    //integration process

    spll_obj->sin[0]=spll_obj->sin[1]+SPLL_Qmpy((SPLL_Qmpy(spll_obj->delta_t,spll_obj->wo)),spll_obj->cos[1]);

    spll_obj->cos[0]=spll_obj->cos[1]-SPLL_Qmpy((SPLL_Qmpy(spll_obj->delta_t,spll_obj->wo)),spll_obj->sin[1]);

    if(spll_obj->sin[0]>SPLL_Q(0.99))

    spll_obj->sin[0]=SPLL_Q(0.99);

    else if(spll_obj->sin[0]<SPLL_Q(-0.99))

    spll_obj->sin[0]=SPLL_Q(-0.99);

    if(spll_obj->cos[0]>SPLL_Q(0.99))

    spll_obj->cos[0]=SPLL_Q(0.99);

    else if(spll_obj->cos[0]<SPLL_Q(-0.99))

    spll_obj->cos[0]=SPLL_Q(-0.99);

    // spll_obj->theta[0]=spll_obj->theta[1]+SPLL_Qmpy(spll_obj->wn,SPLL_Q(0.00001591549));

    spll_obj->theta[0]=spll_obj->theta[1]+(spll_obj->wo*(0.00000795));

    //added by me

    if(spll_obj->sin[0]>SPLL_Q(0.0) && spll_obj->sin[1]<=SPLL_Q(0.0))

    {

    spll_obj->theta[0]=SPLL_Q(0.0);

    }

    spll_obj->theta[1]=spll_obj->theta[0];

    spll_obj->sin[1]=spll_obj->sin[0];

    spll_obj->cos[1]=spll_obj->cos[0];

    }

    #define

    SPLL_1ph_MACRO(v) \

    /* Phase Detect*/ \

    v.Upd[0]=SPLL_Qmpy(v.AC_input,v.cos[1]); \

    /* Notch Filter*/ \

    v.ynotch[0]=-SPLL_Qmpy(v.notch_coeff.A1_notch,v.ynotch[1])-SPLL_Qmpy(v.notch_coeff.A2_notch,v.ynotch[2])+SPLL_Qmpy(v.notch_coeff.B0_notch,v.Upd[0])+SPLL_Qmpy(v.notch_coeff.B1_notch,v.Upd[1])+SPLL_Qmpy(v.notch_coeff.B2_notch,v.Upd[2]); \

    /* Update Upd Array for future use*/ \

    v.Upd[2]=v.Upd[1]; \

    v.Upd[1]=v.Upd[0]; \

    /* LPF*/ \

    v.ylf[0]=-SPLL_Qmpy(v.lpf_coeff.A1_lf,v.ylf[1])+SPLL_Qmpy(v.lpf_coeff.B0_lf,v.ynotch[0])+SPLL_Qmpy(v.lpf_coeff.B1_lf,v.ynotch[1]); \

    /* Update Array for future use*/ \

    v.ynotch[2]=v.ynotch[1]; \

    v.ynotch[1]=v.ynotch[0]; \

    v.ylf[1]=v.ylf[0]; \

    /*VCO*/ \

    v.wo=v.wn+v.ylf[0]; \

    /* integration process */ \

    v.sin[0]=v.sin[1]+SPLL_Qmpy((SPLL_Qmpy(v.delta_t,v.wo)),v.cos[1]); \

    v.cos[0]=v.cos[1]-SPLL_Qmpy((SPLL_Qmpy(v.delta_t,v.wo)),v.sin[1]); \

    if(v.sin[0]>SPLL_Q(0.99)) \

    v.sin[0]=SPLL_Q(0.99); \

    else if(v.sin[0]<SPLL_Q(-0.99)) \

    v.sin[0]=SPLL_Q(-0.99); \

    if(v.cos[0]>SPLL_Q(0.99)) \

    v.cos[0]=SPLL_Q(0.99); \

    else if(v.cos[0]<SPLL_Q(-0.99)) \

    v.cos[0]=SPLL_Q(-0.99); \

    v.theta[0]=v.theta[1]+SPLL_Qmpy(v.wn,SPLL_Q(0.00001591549)); \

    if(v.sin[0]>SPLL_Q(0.0) && v.sin[1]<=SPLL_Q(0.0)) \

    { \

    v.theta[0]=SPLL_Q(0.0); \

    } \

    v.theta[1]=v.theta[0]; \

    v.sin[1]=v.sin[0]; \

    v.cos[1]=v.cos[0]; \

    #endif

  • Please can you answer my question? thanks a lot

    Reguards

  • Dear Manish,

    Thank you very much for your patience.

    I have include your 3414.SPLL_1ph.h, and my snippet code is:

    SPLL_1ph_run(&spll1);

    Vac_in=(long)((long)AdcResult.ADCRESULT1<<9)-Offset_Volt;

    spll1.AC_input=Vac_in>>1;

    InvSine = (long)(spll1.sin[0])>>6; // InvSine is in Q15

    theta = (long)((long)(spll1.theta[0])>>6)+_IQ15(phase_diff); //theta is in Q15

    sen_theta = _IQ15sin(theta);

    The result is show in the following picture:

    Where the sinusoidal wave is InvSine (fully locked with the grid wave), and the sawtooth wave is sen_theta!

    certainly made ​​a mistake, I will be grateful if you can help!

    Thanks Reguards

  • Please Someone reply!

    Thanks

  • Correction to your code

    Vac_in=(long)((long)AdcResult.ADCRESULT1<<9)-Offset_Volt;

    spll1.AC_input=Vac_in>>1;

    SPLL_1ph_run(&spll1);

    InvSine = (long)(spll1.sin[0])>>6; // InvSine is in Q15

    theta = (long)((long)(spll1.theta[0])>>6)+_IQ15(phase_diff); //theta is in Q15

    sen_theta = _IQ15sin(theta);

    You should update your Vac value before calling the PLL,

    I guess the theta locks,You should try out a few things and understand how to get the value shifted by theta, 

    try increasing the phase diff value to see of it is not a resolution problem,

  • Dear Manish,

    I have a far simpler question about using your SPLL in my project. I understand how you've implemented SPLL, but I keep getting the error "error #10234-D: unresolved symbols remain".

    I've been following the SolarExplorer example given in the controlsuite, but I do not need, for example, MPPT, or pidGrando, or sine wave analysis; I just want to use the SPLL_1ph_run function call.

    In CCSv5 using TMS320F28035 (but not the floating point core)

    1)  I've added the SPLL_1ph.hIQmathLib.h, and PeripheralHeaderIncludes.h files to the include file path, and I've also included the library "C:\TI\controlSUITE\libs\math\IQmath\v15b\lib\IQmath_fpu32.lib" to the linker path. I include the three in the main.c file

    2) above the main( ) function, I write:

    SPLL_1ph spll1;
    int32 Vac_in;
    int32 Grid_Freq = 50;

    3) I call SPLL_1ph_init(50,_IQ21(0.00005),&spll1); in the main function before I reach the while(1) loop.

    4) In my interrupt loop:

      Vac_in=(int32)(AdcResult.ADCRESULT1 - 2048);    // shift to convert to Q21
      spll1.AC_input=Vac_in>>1;
      SPLL_1ph_run(&spll1);

    I want to avoid adding unnecessary files to the project, so I've resisted exactly copying every single include file that you've used, and tried to keep just the essentials.

    In fact, the build error itself is below:

    undefined first referenced                   
      symbol       in file                        
     --------- ----------------                   
     __IQ21    ./SinglePhaseInverterClosedLoop.obj
     __IQ21mpy ./SinglePhaseInverterClosedLoop.obj

    error #10234-D: unresolved symbols remain
    error #10010: errors encountered during linking; "SinglePhaseInverter.out" not

  • hello

     I am ever seen some article about the method you just mentioned to sychronize with the grid,which based on the axies transformation,it has better rubust,now I am working with the three phase power factor correction, in the ogrith ,I want to get the grid angle in realtime,based on your anwsers,I wonder if there is any source code about the 3-phase PLL using tms320f28x series DSP? if there is,please contact me.

     

                                   thanks!

  • Brian,

    Apologies this surely was missed by me, I

    1. F28035 is a fixed point processor hence you should link the regular IQmath Lib without the fpu32 extension, this will solve your compiling issues.

  • hello, I need a example of phased locked loop, please.

  • Hi Saniago,

    Manish refers to example code for a single-phase PLL earlier in the thread that is available via ControlSUITE.