Tool/software:
pll code /******************************************************************************* * Includes ******************************************************************************/ #include "measurements.h" #include "protections.h" #include "pll.h" #include "stdlib.h" #include "math.h" #include "stdlib.h" #include "IQmathLib.h" #include "control.h" #include "isr.h" #include "state.h" #include "init.h" #include "cust_math.h" /******************************************************************************* * Defines ******************************************************************************/ #define PI 3.14159265f #define TWO_PI (2.0f * PI) #define ANGLE_THRESHOLD_HIGH (4.18879f) // ~240° in radians #define ANGLE_THRESHOLD_LOW (2.09439f) // ~120° in radians /******************************************************************************* * Enums ******************************************************************************/ /******************************************************************************* * Structures ******************************************************************************/ /******************************************************************************* * Macros ******************************************************************************/ /******************************************************************************* * Local Function Prototypes ******************************************************************************/ /******************************************************************************* * Local Variables ******************************************************************************/ float32_t uf32_angle; uint16_t g_ui16_Pll_state = 0; float32_t FrequencyInHz; float32_t sampling_frequency = (INIT_mSWITCHING_FREQ * 2.0F); PLL_tzPLL_REG tzPLLReg; /******************************************************************************* * Local Constants ******************************************************************************/ /*============================================================================= @brief Write EEPROM Page @param void @return void ============================================================================ */ void PLL_fnGridPLL(void) { if (tzPLLReg.uiGridPhaseSeq == 1) { tzPLLReg.pll_angle = tzPLLReg.pll_angle+ tzPLLReg.pll_angle_step; } else { tzPLLReg.pll_angle = tzPLLReg.pll_angle- tzPLLReg.pll_angle_step; } if(tzPLLReg.pll_angle>=TWO_PI)tzPLLReg.pll_angle-=TWO_PI; if(tzPLLReg.pll_angle<0)tzPLLReg.pll_angle+=TWO_PI; tzPLLReg.Sine_theta = sinf( tzPLLReg.pll_angle); tzPLLReg.Cos_theta = cosf( tzPLLReg.pll_angle); /// clarke's transformation voltage.alpha=1.5*tzACDerivedValues.fVrnPhase; voltage.beta=(tzACDerivedValues.fVynPhase-tzACDerivedValues.fVbnPhase)*(1.7320508/2.0); /// sogi /// // if (tzPLLReg.ePLLState == PLL_LOCKED) // { tzPLLReg.V_alpha_filtered = voltage.alpha; tzPLLReg.V_beta_filtered = voltage.beta; //} //// park's transformation ///// tzPLLReg.V_daxis=tzPLLReg.V_alpha_filtered* tzPLLReg.Cos_theta+tzPLLReg.V_beta_filtered*tzPLLReg.Sine_theta; tzPLLReg.V_qaxis=tzPLLReg.V_beta_filtered*tzPLLReg.Cos_theta-tzPLLReg.V_alpha_filtered*tzPLLReg.Sine_theta; tzPLLReg.V_qaxis_filtered = MATH_fnLowPassFilter( 10, tzPLLReg.V_qaxis, tzPLLReg.V_qaxis_filtered, sampling_frequency); tzPLLReg.V_daxis_filtered = MATH_fnLowPassFilter( 10, tzPLLReg.V_daxis, tzPLLReg.V_daxis_filtered, sampling_frequency); if (tzPLLReg.uiGridPhaseSeq == 1) { tzPLLLoop.Fbk=-tzPLLReg.V_qaxis; } else { tzPLLLoop.Fbk=tzPLLReg.V_qaxis; } tzPLLReg.Volt_peak = sqrtf((tzPLLReg.V_alpha_filtered * tzPLLReg.V_alpha_filtered) + (tzPLLReg.V_beta_filtered * tzPLLReg.V_beta_filtered)) * (0.66667F); if (tzPLLReg.Volt_peak < 20) //50 { PLL_fnResetPLLParams(); } switch (tzPLLReg.ePLLState) { case PLL_INIT: { if (tzPLLReg.Volt_peak > 40) //100 { ++tzPLLReg.pll_timer; if (tzPLLReg.pll_timer > 100) { tzPLLReg.ePLLState = FIRST_ZERO_CROSSING; } } break; } case FIRST_ZERO_CROSSING: { uf32_angle = atan2f(tzPLLReg.V_beta_filtered, tzPLLReg.V_alpha_filtered); if (uf32_angle < 0) { uf32_angle = (TWO_PI) + uf32_angle; } if ((tzPLLReg.pll_angle> ANGLE_THRESHOLD_HIGH) && (uf32_angle < ANGLE_THRESHOLD_LOW)) { tzPLLReg.uiGridPhaseSeq = 1; tzPLLReg.ePLLState = SECOND_ZERO_CROSSING; } else if ((uf32_angle > ANGLE_THRESHOLD_HIGH) && (tzPLLReg.pll_angle < ANGLE_THRESHOLD_LOW)) { tzPLLReg.uiGridPhaseSeq = 0; tzPLLReg.ePLLState = SECOND_ZERO_CROSSING; } tzPLLReg.pll_angle= uf32_angle; tzPLLReg.pll_state_count = 0; break; } case SECOND_ZERO_CROSSING: { tzPLLReg.pll_state_count++; uf32_angle = atan2f(tzPLLReg.V_beta_filtered, tzPLLReg.V_alpha_filtered); if (uf32_angle < 0) { uf32_angle = (TWO_PI) + uf32_angle; } if (tzPLLReg.uiGridPhaseSeq == 1) { if ((tzPLLReg.pll_angle > ANGLE_THRESHOLD_HIGH) && (uf32_angle < ANGLE_THRESHOLD_LOW)) { tzPLLReg.frequency = sampling_frequency / tzPLLReg.pll_state_count; tzPLLReg.ePLLState = PLL_LOCKED; } else if ((uf32_angle > ANGLE_THRESHOLD_HIGH) && (tzPLLReg.pll_angle < ANGLE_THRESHOLD_LOW)) { PLL_fnResetPLLParams(); } } else { if ((uf32_angle > ANGLE_THRESHOLD_HIGH) && (tzPLLReg.pll_angle < ANGLE_THRESHOLD_LOW)) { tzPLLReg.frequency = -(sampling_frequency / tzPLLReg.pll_state_count); tzPLLReg.ePLLState = PLL_LOCKED; } else if ((tzPLLReg.pll_angle > ANGLE_THRESHOLD_HIGH) && (uf32_angle < ANGLE_THRESHOLD_LOW)) { PLL_fnResetPLLParams(); } } tzPLLReg.pll_angle = uf32_angle; break; } case PLL_LOCKED: { CTRL_PI_LOOP(tzPLLLoop); // tzPLLReg.pll_angle_step = ((tzPLLLoop.Out * 6.28) / sampling_frequency); tzPLLReg.frequency = MATH_fnLowPassFilter(500, tzPLLLoop.Out, tzPLLReg.frequency, sampling_frequency); FrequencyInHz = tzPLLReg.frequency; if (abs(tzPLLReg.V_qaxis_filtered) > 25.0F) { if(tzTimers.ui_pll_sync_timer >= 10000U) { tuSWFaults.bit.btPLLSyncError = 1U; } else { tzTimers.ui_pll_sync_timer += 1; } } else if (abs(tzPLLReg.V_qaxis_filtered) < 5.0F) { if(tzTimers.ui_pll_sync_timer > 0U) { tzTimers.ui_pll_sync_timer--; } } break; } } } /*============================================================================= @brief Read @param void @return void ============================================================================ */ void PLL_fnResetPLLParams(void) { CTRL_RESET_PI_LOOP(tzPLLLoop); tzPLLReg.pll_angle = 0; tzPLLReg.pll_angle_step= 0; tzPLLReg.frequency = 0; tzPLLReg.ePLLState = PLL_INIT; FrequencyInHz = 50.00; tzPLLReg.V_qaxis_filtered = 0; } /******************************************************************************* * End of File ******************************************************************************/ Control loop values CTRL_tzLOOP_PARAMS tzPLLLoop = { .Fbk = 0, .Ref = 0, .Out = 0, .Kp =0.01, .TsKi = 1.57e-6, .i1 = 0, .ui = 0, .up = 0, .v1 = 0, .w1 = 0, .Umax = 65, .Umin = 45 }; Switching frequency is 20KHz
I am working on an AC-DC converter and currently implementing the PLL logic. When I provide an AC input of 50 V at 50 Hz, the PLL enters the locked state, but the variable tzPLLReg.frequency
consistently shows 45 Hz, even though the actual frequency is 50 Hz (from expression window.)
When I change the input frequency to 40 Hz or other values, the PLL still remains in the PLL_LOCKED
state. However, if I vary the voltage, the PLL state changes accordingly.
This indicates that the voltage detection is working, but the frequency measurement is inaccurate. I am attaching all related program files for reference. Please help me resolve this issue.
I need to get frequency as 50 Hz accurately it should not vary from 50Hz (0.1% deviation is fine).