├── .gitignore ├── examples ├── CMakeLists.txt ├── FLL │ ├── FLL.slx │ ├── response.png │ ├── ReadMe.md │ ├── test_fll_plot.m │ ├── CMakeLists.txt │ └── test_fll.c └── SOGI_PLL │ ├── SOGI_PLL.slx │ ├── response.png │ ├── ReadMe.md │ ├── CMakeLists.txt │ ├── test_sogi_pll_plot.m │ └── test_sogi_pll.c ├── SConscript ├── CMakeLists.txt ├── README.md ├── include ├── fll.h └── pll_sogi.h ├── src ├── fll.c └── pll_sogi.c └── .clang-format /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-debug/* 2 | .idea/* 3 | .vscode/* 4 | build/* 5 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(FLL) 2 | add_subdirectory(SOGI_PLL) 3 | -------------------------------------------------------------------------------- /examples/FLL/FLL.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haodongnj/PLL/HEAD/examples/FLL/FLL.slx -------------------------------------------------------------------------------- /examples/FLL/response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haodongnj/PLL/HEAD/examples/FLL/response.png -------------------------------------------------------------------------------- /examples/FLL/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Frequency response of FLL 2 | 3 | ![Frequency response of FLL](response.png) 4 | -------------------------------------------------------------------------------- /examples/SOGI_PLL/SOGI_PLL.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haodongnj/PLL/HEAD/examples/SOGI_PLL/SOGI_PLL.slx -------------------------------------------------------------------------------- /examples/SOGI_PLL/response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haodongnj/PLL/HEAD/examples/SOGI_PLL/response.png -------------------------------------------------------------------------------- /examples/SOGI_PLL/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Frequency response of SOGI-PLL 2 | 3 | ![Frequency response of SOGI-PLL](response.png) -------------------------------------------------------------------------------- /examples/FLL/test_fll_plot.m: -------------------------------------------------------------------------------- 1 | clear ; 2 | close all ; 3 | 4 | d = load('result.txt') ; 5 | 6 | t = d(:, 1) ; 7 | f = d(:, 2) ; 8 | 9 | plot(t, f) 10 | xlabel('Time(s)') 11 | ylabel('Frequency(Hz)') 12 | title('FLL response') -------------------------------------------------------------------------------- /SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | cwd = GetCurrentDir() 4 | src = Glob('*.c') 5 | path = [cwd + '/include'] 6 | 7 | if GetDepend('PKG_USING_PLL'): 8 | src += Glob('src/*.c') 9 | 10 | group = DefineGroup('PLL', src, depend = ['PKG_USING_PLL'], CPPPATH = path) 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(PLL) 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | add_library(PLL STATIC 5 | src/pll_sogi.c 6 | src/fll.c 7 | ) 8 | 9 | target_include_directories(PLL PRIVATE 10 | include 11 | ) 12 | 13 | 14 | add_subdirectory(examples) -------------------------------------------------------------------------------- /examples/FLL/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(test_fll) 2 | cmake_minimum_required(VERSION 3.10.0) 3 | 4 | add_executable(test_fll 5 | test_fll.c 6 | ../../src/fll.c) 7 | 8 | target_include_directories(test_fll PRIVATE ../../include) 9 | if (UNIX) 10 | target_link_libraries(test_fll PRIVATE m) 11 | endif (UNIX) -------------------------------------------------------------------------------- /examples/SOGI_PLL/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(test_sogi_pll) 2 | cmake_minimum_required(VERSION 3.10.0) 3 | 4 | add_executable(test_sogi_pll 5 | test_sogi_pll.c 6 | ../../src/pll_sogi.c) 7 | 8 | target_include_directories(test_sogi_pll PRIVATE ../../include) 9 | if (UNIX) 10 | target_link_libraries(test_sogi_pll m) 11 | endif (UNIX) 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PLL and FLL 2 | 3 | - SOGI_PLL: second order generalized integrator based phase-locked loop. 4 | - FLL: second order generalized integrator based frequency-locked loop. 5 | 6 | ## References 7 | 8 | 1. [Overview of SOGI-Based Single-Phase Phase-Locked Loops for Grid Synchronization Under Complex Grid Conditions](https://ieeexplore.ieee.org/document/9369398) 9 | -------------------------------------------------------------------------------- /examples/SOGI_PLL/test_sogi_pll_plot.m: -------------------------------------------------------------------------------- 1 | clear ; 2 | close all ; 3 | 4 | data = load('result.txt'); 5 | sine_wave = data(:, 1) ; 6 | phase_wave = data(:, 2) ; 7 | sine_detect = data(:,3); 8 | angle_freq = data(:,4) ; 9 | t = data(:,5); 10 | 11 | plot(t, sine_wave); 12 | hold on; 13 | plot(t, sine_detect); 14 | xlabel('Time(s)'); 15 | ylabel('Signal'); 16 | hold off; 17 | 18 | figure 19 | plot(t, phase_wave) ; 20 | xlabel('Time(s)'); 21 | ylabel('Phase(rad)'); 22 | 23 | figure 24 | plot(t, angle_freq/(2 * pi)) ; 25 | xlabel('Time(s)'); 26 | ylabel('Frequency(Hz)'); -------------------------------------------------------------------------------- /examples/FLL/test_fll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /// in case of compiling under MS windows 6 | #ifndef M_PI 7 | #define M_PI 3.14159265358979323846 8 | #endif 9 | 10 | int main(int argc, char const *argv[]) { 11 | FLL_t s; 12 | float freq = 0, sine_wave = 0, t; 13 | 14 | init_fll(&s, 1.414213562, 0.5, 5e-5, 50); 15 | 16 | FILE *fp = fopen("result.txt", "w"); 17 | 18 | for (int i = 0; i < 2e3; i++) { 19 | t = (i + 1) * 5e-5; 20 | sine_wave = sin(2 * M_PI * 50 * t); 21 | freq = calc_fll(&s, 311 * sine_wave); 22 | fprintf(fp, "%f,%f\r\n", t, freq); 23 | } 24 | 25 | fclose(fp); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /include/fll.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDE_FLL_H_ 2 | #define INCLUDE_FLL_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef struct FLL { 9 | float k_gain_sogi; 10 | float gamma; 11 | float sogi_forward_integrator_output; 12 | float sogi_backward_integrator_output; 13 | float update_period; 14 | float freq_radians; 15 | float center_freq_radians; 16 | float freq_Hz; 17 | float fll_integrator; 18 | } FLL_t; 19 | 20 | /** 21 | * @brief initialize FLL_t struct. 22 | * 23 | * @param s pointer to FLL_t struct 24 | * @param k_gain_sogi gain of SOGI 25 | * @param gamma gamma value for SOGI-PLL 26 | * @param dt period of calculation 27 | * @param fc center frequency in Hz 28 | */ 29 | void init_fll(FLL_t *s, float k_gain_sogi, float gamma, float dt, float fc); 30 | 31 | /** 32 | * @brief calculation of FLL. 33 | * 34 | * @param s pointer fo FLL_t struct 35 | * @param signal input signal 36 | * @return float instant calculated frequency 37 | */ 38 | float calc_fll(FLL_t *s, float signal); 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | 44 | #endif// INCLUDE_FLL_H_ 45 | -------------------------------------------------------------------------------- /include/pll_sogi.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDE_PLL_SOGI_H_ 2 | #define INCLUDE_PLL_SOGI_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef struct PLL_SOGI { 9 | float sogi_forward_integrator_output; 10 | float sogi_backward_integrator_output; 11 | float phase_output; 12 | float loop_filter_kp; 13 | float loop_filter_ki; 14 | float ke; 15 | float angle_freq; 16 | float update_period; 17 | float center_angle_freq; 18 | float loop_filter_sum; 19 | 20 | } PLL_SOGI_t; 21 | 22 | /** 23 | * @brief initialize PLL_SOGI_t struct 24 | * 25 | * @param s pointer to PLL_SOGI_t struct 26 | * @param ke gain for error part of SOGI 27 | * @param kp proportional gain for loop filter of PLL 28 | * @param ki integrational gain for loop filter of PLL 29 | * @param dt period for calculation 30 | * @param fc center frequency in Hz 31 | */ 32 | void init_pll_sogi(PLL_SOGI_t *s, float ke, float kp, float ki, float dt, float fc); 33 | 34 | /** 35 | * @brief calculation of PLL. 36 | * 37 | * @param s pointer to PLL_SOGI_t struct 38 | * @param signal input signal 39 | * @return float instant calculated phase 40 | */ 41 | float calc_pll_sogi(PLL_SOGI_t *s, float signal); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif// INCLUDE_PLL_SOGI_H_ 48 | -------------------------------------------------------------------------------- /examples/SOGI_PLL/test_sogi_pll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /// in case of compiling under MS windows 6 | #ifndef M_PI 7 | #define M_PI 3.14159265358979323846 8 | #endif 9 | 10 | static const double ts = 5e-5; 11 | static const double f1 = 49.5; 12 | static const double f2 = 50.5; 13 | static const double amplitude = 311.0; 14 | 15 | int main() { 16 | PLL_SOGI_t s; 17 | double phase = 0, sine_wave = 0; 18 | double theta = 0; 19 | 20 | init_pll_sogi(&s, 2.0, 0.2, 1.0, ts, 50); 21 | 22 | FILE *fp = fopen("result.txt", "w"); 23 | 24 | for (int i = 0; i < 1e4; i++) { 25 | theta += 2 * M_PI * f1 * ts; 26 | sine_wave = sin(theta); 27 | phase = calc_pll_sogi(&s, amplitude * sine_wave); 28 | fprintf(fp, "%lf,%lf,%lf,%lf,%lf\r\n", 29 | sine_wave, 30 | phase, 31 | sin(phase), 32 | s.angle_freq, 33 | i * ts); 34 | } 35 | 36 | // change frequency to f2 here 37 | for (int i = 1e4; i < 2e4; i++) { 38 | theta += 2 * M_PI * f2 * ts; 39 | sine_wave = sin(theta); 40 | phase = calc_pll_sogi(&s, amplitude * sine_wave); 41 | fprintf(fp, "%lf,%lf,%lf,%lf,%lf\r\n", 42 | sine_wave, 43 | phase, 44 | sin(phase), 45 | s.angle_freq, 46 | i * ts); 47 | } 48 | 49 | fclose(fp); 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/fll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef M_PI 5 | #define M_PI 3.14159265358979323846 6 | #endif 7 | 8 | #ifndef M_1_PI 9 | #define M_1_PI 0.31830988618379067153803535746773 10 | #endif 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | void init_fll(FLL_t *s, float k_gain_sogi, float gamma, float dt, float fc) { 17 | s->center_freq_radians = fc * 2 * M_PI; 18 | s->freq_Hz = fc; 19 | s->freq_radians = fc * 2 * M_PI; 20 | 21 | s->k_gain_sogi = k_gain_sogi; 22 | s->gamma = gamma; 23 | s->update_period = dt; 24 | 25 | s->sogi_backward_integrator_output = 0; 26 | s->sogi_forward_integrator_output = 0; 27 | s->fll_integrator = 0; 28 | } 29 | 30 | float calc_fll(FLL_t *s, float signal) { 31 | float e, sogi_input, qv, v, temp, ef; 32 | 33 | e = signal - s->sogi_forward_integrator_output; 34 | sogi_input = e * s->k_gain_sogi; 35 | 36 | qv = s->sogi_backward_integrator_output * s->freq_radians; 37 | 38 | temp = sogi_input - qv; 39 | 40 | temp *= s->freq_radians; 41 | s->sogi_forward_integrator_output += temp * s->update_period; 42 | 43 | s->sogi_backward_integrator_output += s->sogi_forward_integrator_output * s->update_period; 44 | 45 | ef = e * qv; 46 | 47 | s->fll_integrator += -s->gamma * ef * s->update_period; 48 | 49 | s->freq_radians = s->center_freq_radians + s->fll_integrator; 50 | s->freq_Hz = s->freq_radians * M_1_PI * 0.5; 51 | 52 | return s->freq_Hz; 53 | } 54 | 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | -------------------------------------------------------------------------------- /src/pll_sogi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /// in case of compiling under MS windows 5 | #ifndef M_PI 6 | #define M_PI 3.14159265358979323846 7 | #endif 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void init_pll_sogi(PLL_SOGI_t *s, float ke, float kp, float ki, float dt, float fc) { 14 | s->center_angle_freq = fc * 2 * M_PI; 15 | s->angle_freq = s->center_angle_freq; 16 | s->update_period = dt; 17 | s->ke = ke; 18 | s->loop_filter_ki = ki * s->update_period; 19 | s->loop_filter_kp = kp; 20 | s->phase_output = 0; 21 | s->sogi_backward_integrator_output = 0; 22 | s->sogi_forward_integrator_output = 0; 23 | s->loop_filter_sum = 0; 24 | } 25 | 26 | float calc_pll_sogi(PLL_SOGI_t *s, float signal) { 27 | float error; 28 | 29 | error = signal - s->sogi_forward_integrator_output; 30 | error = s->ke * error; 31 | error -= s->sogi_backward_integrator_output * s->angle_freq; 32 | error *= s->angle_freq; 33 | s->sogi_forward_integrator_output += error * s->update_period; 34 | 35 | s->sogi_backward_integrator_output += s->sogi_forward_integrator_output * s->update_period; 36 | 37 | error = s->sogi_forward_integrator_output * cos(s->phase_output) + 38 | s->sogi_backward_integrator_output * s->angle_freq * sin(s->phase_output); 39 | s->loop_filter_sum += error * s->loop_filter_ki; 40 | s->angle_freq = s->center_angle_freq + s->loop_filter_sum + s->loop_filter_kp * error; 41 | s->phase_output += s->angle_freq * s->update_period; 42 | 43 | if (s->phase_output > 2 * M_PI) { 44 | s->phase_output -= 2 * M_PI; 45 | } 46 | 47 | return s->phase_output; 48 | } 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: None 6 | AlignOperands: Align 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Always 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Always 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | CompactNamespaces: false 38 | ContinuationIndentWidth: 8 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: All 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: false 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 0 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: Never 67 | --------------------------------------------------------------------------------