单相逆变并网的学习代码SOGIDQ锁相 纯代码仿真锁相环并网stm32代码先扔个Matlab仿真代码镇楼% SOGI正交信号生成 function [alpha, beta] SOGI(v_grid, w0, Ts) persistent x1 x2; if isempty(x1) x1 0; x2 0; end k 1.414; x1_new x1 Ts*(v_grid*k*w0 - x2*w0^2 - x1*2*k*w0); x2 x2 Ts*x1; alpha x1_new; beta x2; x1 x1_new; end % DQ变换核心 theta cumsum(w*Ts); % 相位积分 [d, q] [cos(theta), sin(theta); -sin(theta), cos(theta)] * [alpha; beta];这段代码藏着两个关键点SOGI的微分方程实现用了前向欧拉法注意这里的状态变量x1、x2要持久化保存。系数k取根号2可不是随便拍的脑袋这个值能让正交信号生成达到最佳动态响应。硬件实战时得注意定点数处理看STM32的ADC中断服务函数// 在stm32f4xx_it.c里 void ADC_IRQHandler(void){ static int32_t x10, x20; int16_t adc_val ADC1-DR; // 读取电网电压采样值 // 定点数运算Q15格式 int32_t input adc_val * 2896; // 28961.414*204812位ADC量程 int32_t temp _SSAT((x1*7258 - x2*268435) 15, 16); // 72582*k*w0*Ts x1 x1 ((input - temp) 4); x2 x2 (x1 4); // 更新全局变量 pll_alpha x1 12; // 降回实际量纲 pll_beta x2 12; }这里用Q15格式处理小数运算右移操作代替除法。特别注意_SSAT这个饱和指令防止运算溢出这是嵌入式开发经常埋雷的地方。采样频率设置为10kHz时Ts0.0001需要换算成Q15的系数具体数值得用matlab提前算好。单相逆变并网的学习代码SOGIDQ锁相 纯代码仿真锁相环并网stm32代码锁相环闭环调节部分才是灵魂void TIM6_DAC_IRQHandler(void){ // 10kHz定时器中断 static float pi_out 0.0f; float q_error pll_beta * cos_theta - pll_alpha * sin_theta; // 抗饱和PI控制器 pi_out 0.003f * q_error; // Ki0.003 float output 314.16f 0.5f * q_error pi_out; // Kp0.5 // 更新相位 theta output * 0.0001f; // Ts0.0001 theta fmod(theta, 6.283185307f); // 更新正余弦表 cos_theta arm_cos_f32(theta); sin_theta arm_sin_f32(theta); }这里用了CMSIS的DSP库加速三角函数计算实测在72MHz主频下耗时约1.2us。注意PI控制器的抗饱和处理——当q_error持续过大时需要限制积分项这里简化为系数调节。相位变量theta必须做模运算否则跑几天就会溢出。调参时有个骚操作先把PI参数设为0用信号发生器给50Hz正弦波看q_error能否收敛到0。若出现相位来回震荡把Kp调小若跟踪速度慢适当增大Ki。实际调试中发现电网电压谐波会影响锁相精度这时在SOGI后加个移动平均滤波器有奇效。最后来个并网同步的判断逻辑if(fabs(grid_freq - 50.0f) 0.5f fabs(grid_phase - inverter_phase) 0.087f) { // 5度相位差 GRID_SYNC_LED_ON(); enable_inverter(); } else { trigger_soft_start(); }这个阈值设置要结合具体硬件响应速度曾有个兄弟设了0.1度相位差结果继电器噼里啪啦乱跳。实测在相位差3度、频差0.3Hz内并网电流冲击最小。
锁相环这玩意儿在并网逆变器里就像老司机的方向盘,没它系统分分钟跑偏。今儿咱们扒一扒SOGIDQ这个锁相方案,直接上干货代码,手把手教你从仿真玩到STM32实战
单相逆变并网的学习代码SOGIDQ锁相 纯代码仿真锁相环并网stm32代码先扔个Matlab仿真代码镇楼% SOGI正交信号生成 function [alpha, beta] SOGI(v_grid, w0, Ts) persistent x1 x2; if isempty(x1) x1 0; x2 0; end k 1.414; x1_new x1 Ts*(v_grid*k*w0 - x2*w0^2 - x1*2*k*w0); x2 x2 Ts*x1; alpha x1_new; beta x2; x1 x1_new; end % DQ变换核心 theta cumsum(w*Ts); % 相位积分 [d, q] [cos(theta), sin(theta); -sin(theta), cos(theta)] * [alpha; beta];这段代码藏着两个关键点SOGI的微分方程实现用了前向欧拉法注意这里的状态变量x1、x2要持久化保存。系数k取根号2可不是随便拍的脑袋这个值能让正交信号生成达到最佳动态响应。硬件实战时得注意定点数处理看STM32的ADC中断服务函数// 在stm32f4xx_it.c里 void ADC_IRQHandler(void){ static int32_t x10, x20; int16_t adc_val ADC1-DR; // 读取电网电压采样值 // 定点数运算Q15格式 int32_t input adc_val * 2896; // 28961.414*204812位ADC量程 int32_t temp _SSAT((x1*7258 - x2*268435) 15, 16); // 72582*k*w0*Ts x1 x1 ((input - temp) 4); x2 x2 (x1 4); // 更新全局变量 pll_alpha x1 12; // 降回实际量纲 pll_beta x2 12; }这里用Q15格式处理小数运算右移操作代替除法。特别注意_SSAT这个饱和指令防止运算溢出这是嵌入式开发经常埋雷的地方。采样频率设置为10kHz时Ts0.0001需要换算成Q15的系数具体数值得用matlab提前算好。单相逆变并网的学习代码SOGIDQ锁相 纯代码仿真锁相环并网stm32代码锁相环闭环调节部分才是灵魂void TIM6_DAC_IRQHandler(void){ // 10kHz定时器中断 static float pi_out 0.0f; float q_error pll_beta * cos_theta - pll_alpha * sin_theta; // 抗饱和PI控制器 pi_out 0.003f * q_error; // Ki0.003 float output 314.16f 0.5f * q_error pi_out; // Kp0.5 // 更新相位 theta output * 0.0001f; // Ts0.0001 theta fmod(theta, 6.283185307f); // 更新正余弦表 cos_theta arm_cos_f32(theta); sin_theta arm_sin_f32(theta); }这里用了CMSIS的DSP库加速三角函数计算实测在72MHz主频下耗时约1.2us。注意PI控制器的抗饱和处理——当q_error持续过大时需要限制积分项这里简化为系数调节。相位变量theta必须做模运算否则跑几天就会溢出。调参时有个骚操作先把PI参数设为0用信号发生器给50Hz正弦波看q_error能否收敛到0。若出现相位来回震荡把Kp调小若跟踪速度慢适当增大Ki。实际调试中发现电网电压谐波会影响锁相精度这时在SOGI后加个移动平均滤波器有奇效。最后来个并网同步的判断逻辑if(fabs(grid_freq - 50.0f) 0.5f fabs(grid_phase - inverter_phase) 0.087f) { // 5度相位差 GRID_SYNC_LED_ON(); enable_inverter(); } else { trigger_soft_start(); }这个阈值设置要结合具体硬件响应速度曾有个兄弟设了0.1度相位差结果继电器噼里啪啦乱跳。实测在相位差3度、频差0.3Hz内并网电流冲击最小。