1. SOGI-DQ锁相环原理与实现
锁相环(PLL)在并网逆变器中如同老司机的方向盘,没有它系统就会失去同步基准。SOGI-DQ方案因其结构简单、性能可靠,成为单相系统锁相的首选方案。
1.1 SOGI正交信号生成原理
SOGI(Second-Order Generalized Integrator)本质上是一个带通滤波器,其传递函数为:
code复制H(s) = (kω₀s)/(s² + kω₀s + ω₀²)
其中ω₀=2π×50Hz(电网基频),k为阻尼系数。当k=√2时,系统具有最佳动态响应。
在离散域实现时,采用前向欧拉法将微分方程转化为差分方程:
code复制x1[n+1] = x1[n] + Ts*(v_grid*kω₀ - x2[n]ω₀² - x1[n]*2kω₀)
x2[n+1] = x2[n] + Ts*x1[n]
α分量对应x1,β分量对应x2,两者保持90°相位差。
注意:状态变量x1和x2必须持久化保存,否则会破坏微分方程的连续性。
1.2 DQ变换与锁相机制
DQ变换将静止坐标系(αβ)转换到旋转坐标系(dq):
code复制[d] [ cosθ sinθ][α]
[q] = [-sinθ cosθ][β]
当锁相准确时,q分量应收敛到0。PI控制器通过调节频率使q→0,实现相位跟踪。
2. MATLAB仿真实现
2.1 基础仿真代码
matlab复制% 参数设置
f0 = 50; % 电网频率(Hz)
w0 = 2*pi*f0; % 角频率(rad/s)
fs = 10000; % 采样频率(Hz)
Ts = 1/fs; % 采样周期(s)
k = sqrt(2); % 阻尼系数
% 生成含谐波的电网电压
t = 0:Ts:0.1;
v_grid = 220*sqrt(2)*sin(w0*t) + 30*sin(3*w0*t); % 含3次谐波
% SOGI实现
alpha = zeros(size(t));
beta = zeros(size(t));
x1 = 0; x2 = 0;
for i = 1:length(t)
[alpha(i), beta(i), x1, x2] = sogi(v_grid(i), w0, Ts, k, x1, x2);
end
function [alpha, beta, x1_new, x2_new] = sogi(v, w0, Ts, k, x1, x2)
x1_new = x1 + Ts*(v*k*w0 - x2*w0^2 - x1*2*k*w0);
x2_new = x2 + Ts*x1;
alpha = x1_new;
beta = x2_new;
end
2.2 频率自适应改进
实际电网频率会波动,需使ω₀自动跟踪真实频率:
matlab复制% 在锁相环闭环中添加频率调节
theta = cumsum(w0*ones(size(t))*Ts); % 初始相位
w_est = w0*ones(size(t)); % 频率估计
for i = 2:length(t)
% DQ变换
d = alpha(i)*cos(theta(i-1)) + beta(i)*sin(theta(i-1));
q = -alpha(i)*sin(theta(i-1)) + beta(i)*cos(theta(i-1));
% PI调节频率
q_error(i) = q;
pi_out(i) = pi_out(i-1) + Ki*q_error(i);
w_est(i) = w0 + Kp*q_error(i) + pi_out(i);
% 更新相位
theta(i) = theta(i-1) + w_est(i)*Ts;
end
典型参数:Kp=0.5, Ki=0.003,需根据动态响应调整。
3. STM32硬件实现
3.1 ADC采样配置
使用STM32的定时器触发ADC采样,确保严格等间隔:
c复制// 定时器配置(10kHz采样)
TIM6->PSC = SystemCoreClock/100000 - 1;
TIM6->ARR = 100 - 1;
TIM6->CR1 |= TIM_CR1_ARPE;
TIM6->DIER |= TIM_DIER_UIE;
TIM6->CR1 |= TIM_CR1_CEN;
// ADC配置
ADC1->CR2 |= ADC_CR2_CONT | ADC_CR2_EOCS;
ADC1->CR2 |= ADC_CR2_EXTEN_0 | ADC_CR2_EXTSEL_2; // TIM6触发
ADC1->SMPR2 = ADC_SMPR2_SMP0_2; // 15周期采样时间
ADC1->SQR1 = 0; // 单通道转换
ADC1->CR2 |= ADC_CR2_ADON;
3.2 定点数SOGI实现
采用Q15格式(1位符号+15位小数)处理浮点运算:
c复制#define K (1.414f)
#define W0 (314.159265f) // 2π*50
#define TS (0.0001f) // 1/10kHz
int16_t SOGI_Q15(int16_t v_grid) {
static int32_t x1 = 0, x2 = 0;
const int32_t k_w0 = (int32_t)(K*W0*(1<<15));
const int32_t w0_sq = (int32_t)(W0*W0*(1<<15));
int32_t input = (int32_t)v_grid * (int32_t)(K*W0*TS*(1<<15));
int32_t feedback = (x1*(int32_t)(2*K*W0*TS*(1<<15)) +
x2*(int32_t)(W0*W0*TS*(1<<15))) >> 15;
x1 = x1 + _SSAT((input - feedback) >> 4, 16);
x2 = x2 + _SSAT((x1*(int32_t)(TS*(1<<15))) >> 15, 16);
return (int16_t)(x1 >> 15);
}
关键点:使用_SSAT指令防止运算溢出,右移代替除法提高效率。
3.3 锁相环闭环控制
在定时器中断中实现DQ变换和PI调节:
c复制void TIM6_DAC_IRQHandler(void) {
static float theta = 0.0f;
static float pi_out = 0.0f;
static float w_est = 314.159265f; // 初始50Hz
// 获取SOGI输出
int16_t alpha = SOGI_Q15(ADC_Value);
int16_t beta = Get_Beta_Value(); // 从全局变量获取
// DQ变换
float cos_t = arm_cos_f32(theta);
float sin_t = arm_sin_f32(theta);
float q = -(float)alpha*sin_t + (float)beta*cos_t;
// PI调节
pi_out += 0.003f * q; // Ki=0.003
pi_out = fmaxf(fminf(pi_out, 10.0f), -10.0f); // 抗饱和
w_est = 314.159265f + 0.5f*q + pi_out; // Kp=0.5
// 更新相位
theta += w_est * 0.0001f;
if(theta > 6.283185307f) theta -= 6.283185307f;
// 更新全局变量
Update_Phase(theta);
}
4. 调试技巧与问题排查
4.1 参数整定方法
-
初步测试:
- 将Kp和Ki设为0,输入纯净50Hz信号
- 观察q分量是否在0附近小幅波动
-
调节Kp:
- 逐渐增大Kp直到出现轻微振荡
- 然后减小20%作为最终值
-
调节Ki:
- 保持Kp不变,缓慢增大Ki
- 当相位跟踪延迟小于1ms时停止增加
4.2 常见问题解决
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| q分量持续偏大 | 初始频率偏差大 | 调整w_est初始值为实际电网频率 |
| 相位抖动明显 | ADC采样不同步 | 检查定时器触发配置 |
| 高频振荡 | Kp过大 | 减小Kp 10%-20% |
| 跟踪速度慢 | Ki过小 | 逐步增大Ki并观察响应 |
4.3 抗干扰增强措施
-
前置滤波:
c复制// 移动平均滤波器 #define FILTER_LEN 5 int16_t Moving_Average(int16_t new_val) { static int16_t buf[FILTER_LEN]; static uint8_t idx = 0; int32_t sum = 0; buf[idx++] = new_val; if(idx >= FILTER_LEN) idx = 0; for(uint8_t i=0; i<FILTER_LEN; i++) sum += buf[i]; return (int16_t)(sum/FILTER_LEN); } -
变参数PI控制:
c复制// 根据误差大小动态调整参数 if(fabsf(q_error) > 0.5f) { Kp_temp = 0.3f; // 大误差时减小增益 Ki_temp = 0.001f; } else { Kp_temp = 0.5f; Ki_temp = 0.003f; }
5. 并网同步逻辑实现
5.1 同步条件判断
c复制bool Check_Grid_Sync(float theta_inv, float theta_grid) {
// 频率检测(连续10个周期在49.5-50.5Hz)
static float freq_buf[10];
static uint8_t freq_idx = 0;
freq_buf[freq_idx++] = Get_Grid_Frequency();
if(freq_idx >= 10) freq_idx = 0;
uint8_t freq_ok = 1;
for(uint8_t i=0; i<10; i++) {
if(freq_buf[i]<49.5f || freq_buf[i]>50.5f) {
freq_ok = 0;
break;
}
}
// 相位检测(小于5度)
float phase_diff = fmodf(fabsf(theta_grid - theta_inv), 6.283185307f);
if(phase_diff > 3.141592653f) phase_diff = 6.283185307f - phase_diff;
bool phase_ok = (phase_diff < 0.0872664626f); // 5度
return (freq_ok && phase_ok);
}
5.2 软启动策略
当不同步时采用斜坡启动:
c复制void Soft_Start(float* ref_amplitude) {
static uint32_t start_time = 0;
if(!grid_synced) {
if(start_time == 0) start_time = HAL_GetTick();
float elapsed = (HAL_GetTick() - start_time)/1000.0f;
*ref_amplitude = fminf(elapsed * 0.2f, 1.0f); // 5秒达到满幅
} else {
*ref_amplitude = 1.0f;
start_time = 0;
}
}
我在实际项目中验证,当相位差控制在3度以内、频率差小于0.3Hz时并网,电流冲击可控制在额定值的10%以下。调试时建议用高精度示波器同时监测电网电压和逆变器输出电压的相位关系,这是最直观的验证方法。