Dear all,
anyone knows if there is PLL algorithm that we may use directly?
thanks a lot!
Regards,
Felix
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.
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.
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 Manish ,
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.
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?
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
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!
I certainly made a mistake, I will be grateful if you can help!
Thanks Reguards
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.h, IQmathLib.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.